Files
kichikuou_system3-sdl2/src/sys/mako.cpp
T
kichikuou 51b65c84af MIDI playback with SDL_mixer
Instead of controlling MIDI device in real time, generate a data stream
in SMF format and feed it to SDL_mixer.
2020-02-15 17:27:34 +09:00

224 lines
5.1 KiB
C++

/*
ALICE SOFT SYSTEM 3 for Win32
[ MAKO ]
*/
#include <SDL.h>
#include <SDL_mixer.h>
#include "mako.h"
#include "mako_midi.h"
#include "dri.h"
// MIX_INIT_FLUIDSYNTH was renamed to MIX_INIT_MID in SDL_mixer 2.0.2
#if (SDL_MIXER_MAJOR_VERSION == 2) && (SDL_MIXER_MINOR_VERSION == 0) && (SDL_MIXER_PATCHLEVEL < 2)
#define MIX_INIT_MID MIX_INIT_FLUIDSYNTH
#endif
MAKO::MAKO(NACT* parent) : nact(parent)
{
// AMUS.DAT, AMSE.DAT
_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) {
WARNING("Mix_OpenAudio failed: %s", Mix_GetError());
}
}
MAKO::~MAKO()
{
Mix_CloseAudio();
Mix_Quit();
// PCM停止
#if defined(_USE_PCM)
PlaySound(NULL, NULL, SND_PURGE);
#endif
}
void MAKO::play_music(int 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;
} else {
MAKOMidi midi(nact, amus);
if (midi.load_mml(page)) {
midi.load_mda(page);
smf = midi.generate_smf(current_max);
SDL_RWops *rwops = SDL_RWFromConstMem(smf.data(), smf.size());
mix_music = Mix_LoadMUSType_RW(rwops, MUS_MID, SDL_TRUE /* freesrc */);
if (!mix_music) {
WARNING("Mix_LoadMUS failed: %s", Mix_GetError());
return;
}
if (Mix_PlayMusic(mix_music, -1) != 0) {
WARNING("Mix_PlayMusic failed: %s", Mix_GetError());
return;
}
}
cdda_play = false;
}
}
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();
}
}
}
cdda_play = false;
current_music = current_loop = 0;
}
bool MAKO::check_music()
{
// 再生中でtrue
if (!current_music)
return false;
if (mix_music)
return Mix_PlayingMusic();
return true;
}
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;
}
}
}
void MAKO::play_pcm(int page, bool loop)
{
assert(false);
#if defined(_USE_PCM)
static char header[44] = {
'R' , 'I' , 'F' , 'F' , 0x00, 0x00, 0x00, 0x00, 'W' , 'A' , 'V' , 'E' , 'f' , 'm' , 't' , ' ' ,
0x10, 0x00, 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 0x40, 0x1f, 0x00, 0x00, 0x40, 0x1f, 0x00, 0x00,
0x01, 0x00, 0x08, 0x00, 'd' , 'a' , 't' , 'a' , 0x00, 0x00, 0x00, 0x00
};
// 現在再生中のPCMを停止
PlaySound(NULL, NULL, SND_PURGE);
uint8* buffer = NULL;
int size;
DRI* dri = new DRI();
if((buffer = dri->load(_T("AWAV.DAT"), page, &size)) != NULL) {
// WAV形式 (Only You)
memcpy(wav, buffer, (size < MAX_SAMPLES) ? size : MAX_SAMPLES);
if(loop) {
PlaySound(wav, NULL, SND_ASYNC | SND_MEMORY | SND_LOOP);
} else {
PlaySound(wav, NULL, SND_ASYNC | SND_MEMORY);
}
free(buffer);
} else if((buffer = dri->load(_T("AMSE.DAT"), page, &size)) != NULL) {
// AMSE形式 (乙女戦記)
int total = (size - 12) * 2 + 0x24;
int samples = (size - 12) * 2;
memcpy(wav, header, 44);
wav[ 4] = (total >> 0) & 0xff;
wav[ 5] = (total >> 8) & 0xff;
wav[ 6] = (total >> 16) & 0xff;
wav[ 7] = (total >> 24) & 0xff;
wav[40] = (samples >> 0) & 0xff;
wav[41] = (samples >> 8) & 0xff;
wav[42] = (samples >> 16) & 0xff;
wav[43] = (samples >> 24) & 0xff;
for(int i = 12, p = 44; i < size && p < MAX_SAMPLES - 2; i++) {
wav[p++] = buffer[i] & 0xf0;
wav[p++] = (buffer[i] & 0x0f) << 4;
}
if(loop) {
PlaySound(wav, NULL, SND_ASYNC | SND_MEMORY | SND_LOOP);
} else {
PlaySound(wav, NULL, SND_ASYNC | SND_MEMORY);
}
free(buffer);
}
#endif
}
void MAKO::stop_pcm()
{
#if defined(_USE_PCM)
PlaySound(NULL, NULL, SND_PURGE);
#endif
}
bool MAKO::check_pcm()
{
// 再生中でtrue
#if defined(_USE_PCM)
static char null_wav[45] = {
'R' , 'I' , 'F' , 'F' , 0x25, 0x00, 0x00, 0x00, 'W' , 'A' , 'V' , 'E' , 'f' , 'm' , 't' , ' ' ,
0x10, 0x00, 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 0x40, 0x1f, 0x00, 0x00, 0x40, 0x1f, 0x00, 0x00,
0x01, 0x00, 0x08, 0x00, 'd' , 'a' , 't' , 'a' , 0x01, 0x00, 0x00, 0x00, 0x00
};
return PlaySound(null_wav, NULL, SND_ASYNC | SND_MEMORY | SND_NOSTOP) ? false : true;
#else
return false;
#endif
}