CD-DA BGM playback support with SDL_mixer

This adds -playlist command line option to specify a "playlist" file
which lists music files to be played instead of CD audio tracks.
The format of playlist file is the same as xsystem35's.
This commit is contained in:
kichikuou
2020-02-15 17:27:37 +09:00
parent 51b65c84af
commit 487bd49745
7 changed files with 72 additions and 96 deletions
+1 -1
View File
@@ -3,7 +3,7 @@
#include <jni.h>
#include "mako.h"
MAKO::MAKO(NACT* parent)
MAKO::MAKO(NACT* parent, const char* playlist)
: current_music(0)
, next_loop(0)
{
+1 -1
View File
@@ -6,7 +6,7 @@
#include <emscripten.h>
#include "mako.h"
MAKO::MAKO(NACT* parent)
MAKO::MAKO(NACT* parent, const char* playlist)
: current_music(0)
, next_loop(0)
{
+4 -1
View File
@@ -36,6 +36,7 @@ int main(int argc, char *argv[])
g_window = SDL_CreateWindow(buf, SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, 640, 400, flags);
const char* font_file = DEFAULT_FONT_PATH "MTLc3m.ttf";
const char* playlist = NULL;
const char* game_id = NULL;
char save_dir[256] = "";
@@ -48,12 +49,14 @@ int main(int argc, char *argv[])
strcpy(save_dir, argv[++i]);
else if (strcmp(argv[i], "-fontfile") == 0)
font_file = argv[++i];
else if (strcmp(argv[i], "-playlist") == 0)
playlist = argv[++i];
else if (strcmp(argv[i], "-game") == 0)
game_id = argv[++i];
}
// system3 初期化
NACT* nact = new NACT(game_id, font_file);
NACT* nact = new NACT(game_id, font_file, playlist);
if (save_dir[0]) {
#ifdef __ANDROID__
+55 -68
View File
@@ -16,27 +16,26 @@
#define MIX_INIT_MID MIX_INIT_FLUIDSYNTH
#endif
MAKO::MAKO(NACT* parent) : nact(parent)
MAKO::MAKO(NACT* parent, const char* playlist) :
current_music(0),
next_loop(0),
nact(parent)
{
// AMUS.DAT, AMSE.DAT
int mix_init_flags = MIX_INIT_MID;
if (playlist && load_playlist(playlist))
mix_init_flags |= MIX_INIT_MP3 | MIX_INIT_OGG;
_tcscpy_s(amus, 16, _T("AMUS.DAT"));
_tcscpy_s(amse, 16, _T("AMSE.DAT")); // 実際には使わない
// 再生状況
current_music = current_loop = 0;
current_max = next_loop = 0;
// CD-DA
for(int i = 1; i <= 99; i++) {
cd_track[i] = 0;
}
cdda_play = false;
if (Mix_Init(MIX_INIT_MID) != MIX_INIT_MID) {
WARNING("Mix_Init failed");
}
if (Mix_OpenAudio(44100, AUDIO_S16LSB, 2, 4096) < 0) {
if (Mix_Init(mix_init_flags) != mix_init_flags)
WARNING("Mix_Init(0x%x) failed", mix_init_flags);
if (Mix_OpenAudio(44100, AUDIO_S16LSB, 2, 4096) < 0)
WARNING("Mix_OpenAudio failed: %s", Mix_GetError());
}
}
MAKO::~MAKO()
@@ -44,34 +43,55 @@ MAKO::~MAKO()
Mix_CloseAudio();
Mix_Quit();
// PCM停止
#if defined(_USE_PCM)
PlaySound(NULL, NULL, SND_PURGE);
#endif
}
bool MAKO::load_playlist(const char* path)
{
FILE* fp = fopen(path, "rt");
if (!fp) {
WARNING("Cannot open %s", path);
return false;
}
char buf[256];
while (fgets(buf, sizeof(buf) - 1, fp)) {
char *p = &buf[strlen(buf) - 1];
if (*p == '\n')
*p = '\0';
playlist.push_back(buf[0] ? strdup(buf) : NULL);
}
fclose(fp);
return true;
}
void MAKO::play_music(int page)
{
// 既に同じ曲を再生している
if(current_music == page) {
if(current_music == page)
return;
}
stop_music();
current_music = page;
current_max = next_loop;
if(page < 100 && cd_track[page]) {
// CD-DAで再生
// TODO: fix
// PostMessage(g_hwnd, WM_USER, cd_track[page] + 1, 0);
cdda_play = true;
int track = page < 100 ? cd_track[page] : 0;
if(track) {
if (track < playlist.size() && playlist[track]) {
mix_music = Mix_LoadMUS(playlist[track]);
if (!mix_music) {
WARNING("Mix_LoadMUS failed: %s: %s", playlist[track], Mix_GetError());
return;
}
if (Mix_PlayMusic(mix_music, next_loop ? next_loop : -1) != 0) {
WARNING("Mix_PlayMusic failed: %s", Mix_GetError());
Mix_FreeMusic(mix_music);
return;
}
}
} else {
MAKOMidi midi(nact, amus);
if (midi.load_mml(page)) {
midi.load_mda(page);
smf = midi.generate_smf(current_max);
smf = midi.generate_smf(next_loop);
SDL_RWops *rwops = SDL_RWFromConstMem(smf.data(), smf.size());
mix_music = Mix_LoadMUSType_RW(rwops, MUS_MID, SDL_TRUE /* freesrc */);
if (!mix_music) {
@@ -80,67 +100,34 @@ void MAKO::play_music(int page)
}
if (Mix_PlayMusic(mix_music, -1) != 0) {
WARNING("Mix_PlayMusic failed: %s", Mix_GetError());
Mix_FreeMusic(mix_music);
return;
}
}
cdda_play = false;
}
current_music = page;
}
void MAKO::stop_music()
{
// 現在再生中の場合は停止する
if(current_music) {
if(cdda_play) {
// TODO: fix
// PostMessage(g_hwnd, WM_USER, 0, 0);
} else {
if (mix_music) {
Mix_FreeMusic(mix_music);
mix_music = NULL;
smf.clear();
}
}
if (mix_music) {
Mix_FreeMusic(mix_music);
mix_music = NULL;
smf.clear();
}
cdda_play = false;
current_music = current_loop = 0;
current_music = 0;
}
bool MAKO::check_music()
{
// 再生中でtrue
if (!current_music)
return false;
if (mix_music)
return Mix_PlayingMusic();
return true;
return Mix_PlayingMusic();
}
void MAKO::get_mark(int* mark, int* loop)
{
// TODO: fix
*mark = 0;
*loop = cdda_play ? 0 : current_loop;
}
void MAKO::notify_mci(int status)
{
if(status == -1) {
// 再生に失敗
current_music = current_loop = 0;
return;
}
if(cdda_play) {
current_loop++;
if(current_loop < current_max || current_max == 0) {
// TODO: fix
// PostMessage(g_hwnd, WM_USER, cd_track[current_music] + 1, 0);
} else {
current_music = current_loop = 0;
cdda_play = false;
}
}
*loop = 0;
}
void MAKO::play_pcm(int page, bool loop)
+8 -16
View File
@@ -23,27 +23,14 @@
class MAKO
{
protected:
NACT* nact;
private:
// FM, CD-DA
bool cdda_play;
int current_loop;
int current_max; // Y19
// PCM
char wav[MAX_SAMPLES];
public:
MAKO(NACT* parent);
MAKO(NACT* parent, const char* playlist);
~MAKO();
void play_music(int page);
void stop_music();
bool check_music();
void get_mark(int* mark, int* loop);
void notify_mci(int status);
void play_pcm(int page, bool loop);
void stop_pcm();
@@ -62,22 +49,27 @@ public:
int current_music;
int next_loop; // Y19
int cd_track[100]; // Z
private:
bool load_playlist(const char* path);
NACT* nact;
std::vector<const char*> playlist;
Mix_Music *mix_music;
std::vector<uint8> smf;
char wav[MAX_SAMPLES];
};
#else // Emscripten or Android
class MAKO {
public:
MAKO(NACT* parent);
MAKO(NACT* parent, const char* playlist);
void play_music(int page);
void stop_music();
bool check_music() { return current_music != 0; }
void get_mark(int* mark, int* loop) {}
void notify_mci(int status) {}
void play_pcm(int page, bool loop) {}
void stop_pcm() {}
+2 -7
View File
@@ -16,7 +16,7 @@ extern SDL_Window* g_window;
// 初期化
NACT::NACT(const char* game_id, const char* font_file)
NACT::NACT(const char* game_id, const char* font_file, const char* playlist)
{
mouse_x = mouse_y = 0;
@@ -114,7 +114,7 @@ NACT::NACT(const char* game_id, const char* font_file)
// 各種クラス生成
ags = new AGS(this, font_file);
mako = new MAKO(this);
mako = new MAKO(this, playlist);
#ifdef USE_JOY
// 入力初期化
@@ -409,11 +409,6 @@ int NACT::get_screen_height()
return ags->screen_height;
}
void NACT::notify_mci(int status)
{
mako->notify_mci(status);
}
void NACT::select_cursor()
{
ags->select_cursor();
+1 -2
View File
@@ -231,13 +231,12 @@ private:
void release_console();
public:
NACT(const char* game_id, const char* font_file);
NACT(const char* game_id, const char* font_file, const char* playlist);
~NACT();
void mainloop();
int get_screen_height();
void notify_mci(int status);
void select_cursor();
void select_sound(int dev);