mirror of
https://github.com/kichikuou/system3-sdl2.git
synced 2026-10-06 22:07:56 +03:00
547 lines
15 KiB
C++
547 lines
15 KiB
C++
/*
|
|
ALICE SOFT SYSTEM 3 for Win32
|
|
|
|
[ MAKO - midi ]
|
|
*/
|
|
|
|
#include <windows.h>
|
|
#include <mmsystem.h>
|
|
#include "mako.h"
|
|
#include "dri.h"
|
|
|
|
#define next_mml(p) mml[p].data[mml[p].addr++]
|
|
|
|
// MIDI音源
|
|
union UNION_MIDI_DATA {
|
|
DWORD msg;
|
|
BYTE data[4];
|
|
};
|
|
static UNION_MIDI_DATA midi;
|
|
static HMIDIOUT hMidi;
|
|
|
|
#define send_2bytes(d1, d2) { midi.data[0] = (BYTE)d1; midi.data[1] = (BYTE)d2; midiOutShortMsg(hMidi,midi.msg); }
|
|
#define send_3bytes(d1, d2, d3) { midi.data[0] = (BYTE)d1; midi.data[1] = (BYTE)d2; midi.data[2] = (BYTE)d3 ;midiOutShortMsg(hMidi, midi.msg); }
|
|
|
|
void MAKO::initialize_midi()
|
|
{
|
|
// MIDI音源の初期化
|
|
midiOutOpen(&hMidi, MIDI_MAPPER, NULL, NULL, CALLBACK_NULL);
|
|
}
|
|
|
|
void MAKO::release_midi()
|
|
{
|
|
// MIDI音源の開放
|
|
midiOutClose(hMidi);
|
|
}
|
|
|
|
void MAKO::stop_midi()
|
|
{
|
|
for(int i = 0; i < 10; i++) {
|
|
send_3bytes(0xb0 + i, 0x78, 0x00);
|
|
}
|
|
for(int i = 0; i < 10; i++) {
|
|
send_3bytes(0xb0 + i, 0x79, 0x00);
|
|
}
|
|
}
|
|
|
|
void MAKO::start_midi()
|
|
{
|
|
for(int i = 0; i < 9; i++) {
|
|
play[i].loop_flag = true;
|
|
}
|
|
mute_flag = false;
|
|
|
|
// 再生情報の初期化
|
|
for(int i = 0; i < 9; i++) {
|
|
play[i].timbre = 255;
|
|
play[i].timbre_type = 128;
|
|
play[i].level = 255;
|
|
play[i].reverb = 255;
|
|
play[i].chorus = 255;
|
|
play[i].key_shift = 64;
|
|
play[i].pan = 255;
|
|
|
|
play[i].channel = i;
|
|
play[i].velocity = 120;
|
|
play[i].note = 128;
|
|
|
|
play[i].note_flag = false;
|
|
play[i].loop_cnt = 0;
|
|
play[i].wait_time = 16;
|
|
mml[i].addr = 0;
|
|
}
|
|
|
|
for(int i = 0; i < 3; i++) {
|
|
play[i + 3].timbre = i + 256;
|
|
if(mda[i + 256].bank_select < 128) {
|
|
play[i + 3].timbre_type = 128;
|
|
play[i + 3].channel = i + 3;
|
|
} else {
|
|
play[i + 3].timbre_type = 255 - mda[i + 256].bank_select;
|
|
play[i + 3].channel = 9;
|
|
}
|
|
play[i + 3].level = mda[i + 256].level;
|
|
play[i + 3].reverb = mda[i + 256].reverb;
|
|
play[i + 3].chorus = mda[i + 256].chorus;
|
|
play[i + 3].key_shift = mda[i + 256].key_shift;
|
|
play[i + 3].pan = mda[i + 256].pan;
|
|
}
|
|
|
|
// MIDI音源のGS-RESET
|
|
BYTE gs_reset[11] = {0xf0, 0x41, 0x20, 0x42, 0x12, 0x40, 0x00, 0x7f, 0x00, 0x41, 0xf7};
|
|
MIDIHDR mhMidi;
|
|
ZeroMemory(&mhMidi, sizeof(mhMidi));
|
|
mhMidi.lpData = (LPSTR)gs_reset;
|
|
mhMidi.dwBufferLength = 11;
|
|
mhMidi.dwBytesRecorded = 11;
|
|
|
|
midiOutPrepareHeader(hMidi, &mhMidi, sizeof(mhMidi));
|
|
midiOutLongMsg(hMidi, &mhMidi, sizeof(mhMidi));
|
|
while(!(mhMidi.dwFlags & MHDR_DONE)) {
|
|
SDL_Delay(10);
|
|
}
|
|
midiOutUnprepareHeader(hMidi, &mhMidi, sizeof(mhMidi));
|
|
|
|
// システムリセット、ボリュームリセット
|
|
for(int i = 0; i < 10; i++) {
|
|
send_3bytes(0xb0 + i, 0x79, 0x00);
|
|
}
|
|
for(int i = 0; i < 10; i++) {
|
|
send_3bytes(0xb0 + i, 0x07, 0x64);
|
|
}
|
|
|
|
// SSG 1-3 の音色
|
|
for(int i = 0; i < 3; i++) {
|
|
if(mda[i + 256].bank_select < 128) {
|
|
send_3bytes(0xb3 + i, 0x00, mda[i + 256].bank_select);
|
|
send_3bytes(0xb3 + i, 0x20, 0x00);
|
|
send_2bytes(0xc3 + i, mda[i + 256].program_change);
|
|
send_3bytes(0xb3 + i, 0x07, mda[i + 256].level);
|
|
send_3bytes(0xb3 + i, 0x5b, mda[i + 256].reverb);
|
|
send_3bytes(0xb3 + i, 0x5d, mda[i + 256].chorus);
|
|
send_3bytes(0xb3 + i, 0x0a, mda[i + 256].pan);
|
|
} else {
|
|
send_3bytes(0xb9, 0x07, mda[i + 256].level);
|
|
send_3bytes(0xb9, 0x5b, mda[i + 256].reverb);
|
|
send_3bytes(0xb9, 0x5d, mda[i + 256].chorus);
|
|
send_3bytes(0xb9, 0x0a, mda[i + 256].pan);
|
|
}
|
|
}
|
|
|
|
// タイマーリセット
|
|
prev_time = SDL_GetTicks();
|
|
play_time = 0;
|
|
}
|
|
|
|
void MAKO::play_midi()
|
|
{
|
|
// 経過時間の取得
|
|
Uint32 current_time = SDL_GetTicks();
|
|
if(current_time > prev_time) {
|
|
play_time += (float)(current_time - prev_time);
|
|
prev_time = current_time;
|
|
}
|
|
|
|
// 各パートの更新
|
|
while((play[0].loop_flag || play[1].loop_flag || play[2].loop_flag ||
|
|
play[3].loop_flag || play[4].loop_flag || play[5].loop_flag ||
|
|
play[6].loop_flag || play[7].loop_flag || play[8].loop_flag) && play_time > 0.0) {
|
|
// 1単位時間だけ経過時間を更新する
|
|
for(int i = 0; i < 9; i++) {
|
|
if(play[i].loop_flag && play[i].wait_time) {
|
|
play[i].wait_time--;
|
|
}
|
|
}
|
|
play_time -= (float)(545455.0 / 480.0 / (float)(tempo + 0x40 - tempo_dif));
|
|
|
|
// 1単位時間だけ各パートを更新
|
|
for(int i = 0; i < 9; i++) {
|
|
if(!play[i].loop_flag) {
|
|
play[i].wait_time = 1;
|
|
}
|
|
while(play[i].wait_time == 0) {
|
|
int d0 = next_mml(i), d1, d2, d3;
|
|
if(d0 == 0xff) {
|
|
d1 = next_mml(i);
|
|
d2 = next_mml(i);
|
|
d3 = next_mml(i);
|
|
mml[i].addr = d1 | (d2 << 8) | (d3 << 16);
|
|
if(!play[i].note_flag || mute_flag) {
|
|
// 再生停止または未使用
|
|
play[i].loop_flag = false;
|
|
if(!play[0].loop_flag && !play[1].loop_flag && !play[2].loop_flag &&
|
|
!play[3].loop_flag && !play[4].loop_flag && !play[5].loop_flag &&
|
|
!play[6].loop_flag && !play[7].loop_flag && !play[8].loop_flag) {
|
|
// 全チャンネルが再生停止 (ループしない曲)
|
|
for(int j = 0; j < 10; j++) {
|
|
send_3bytes(0xb0 + j, 0x78, 0x00);
|
|
}
|
|
for(int j = 0; j < 10; j++) {
|
|
send_3bytes(0xb0 + j, 0x79, 0x00);
|
|
}
|
|
current_loop = 1;
|
|
current_music = 0;
|
|
params.current_music = params.next_music = 0;
|
|
return;
|
|
}
|
|
play[i].wait_time = 1;
|
|
} else {
|
|
// 全体としてのループ数を取得
|
|
int loop = ++play[i].loop_cnt;
|
|
for(int j = 0; j < 9; j++) {
|
|
if(loop > play[j].loop_cnt && play[j].loop_flag) {
|
|
loop = play[j].loop_cnt;
|
|
}
|
|
}
|
|
current_loop = loop;
|
|
if(current_loop >= current_max && current_max) {
|
|
// 指定回数だけ再生完了
|
|
for(int j = 0; j < 10; j++) {
|
|
send_3bytes(0xb0 + j, 0x78, 0x00);
|
|
}
|
|
for(int j = 0; j < 10; j++) {
|
|
send_3bytes(0xb0 + j, 0x79, 0x00);
|
|
}
|
|
current_music = 0;
|
|
params.current_music = params.next_music = 0;
|
|
return;
|
|
}
|
|
}
|
|
} else if(d0 < 0x80) {
|
|
int note = d0;
|
|
play[i].wait_time = next_mml(i);
|
|
play[i].wait_time |= next_mml(i) << 8;
|
|
if(play[i].timbre_type != 128) {
|
|
note = drum_map[play[i].timbre_type][note];
|
|
} else {
|
|
note = (note + play[i].key_shift) - 64;
|
|
}
|
|
play[i].note_flag = true;
|
|
play[i].note = note;
|
|
send_3bytes(0x90 + play[i].channel, note, play[i].velocity);
|
|
} else if(d0 == 0x80) {
|
|
play[i].wait_time = next_mml(i);
|
|
play[i].wait_time |= next_mml(i) << 8;
|
|
if(play[i].note != 128) {
|
|
send_3bytes(0x90 + play[i].channel, play[i].note, 0x00);
|
|
}
|
|
play[i].note = 128;
|
|
} else if(d0 == 0xe0) {
|
|
current_mark = next_mml(i);
|
|
} else if(d0 == 0xe1) {
|
|
d1 = next_mml(i);
|
|
play[i].velocity += (d1 > 127) ? (d1 - 256) : d1;
|
|
} else if(d0 == 0xeb) {
|
|
play[i].pan = next_mml(i);
|
|
send_3bytes(0xb0 + play[i].channel, 0x0a, play[i].pan);
|
|
}
|
|
#if !defined(_DPS)
|
|
else if(d0 == 0xec) {
|
|
mute_flag = true;
|
|
}
|
|
#endif
|
|
else if(d0 == 0xf5) {
|
|
int n = next_mml(i);
|
|
if(n != play[i].timbre) {
|
|
if(mda[n].bank_select < 128) {
|
|
// 通常のパート
|
|
play[i].timbre_type = 128;
|
|
play[i].channel = i;
|
|
send_3bytes(0xb0 + play[i].channel, 0x00, mda[n].bank_select);
|
|
send_3bytes(0xb0 + play[i].channel, 0x20, 0x00);
|
|
send_2bytes(0xc0 + play[i].channel, mda[n].program_change);
|
|
} else {
|
|
// ドラムパート (ch.10)
|
|
play[i].timbre_type = 255 - mda[n].bank_select;
|
|
play[i].channel = 9;
|
|
}
|
|
if(play[i].level != mda[n].level) {
|
|
send_3bytes(0xb0 + play[i].channel, 0x07, mda[n].level);
|
|
}
|
|
if(play[i].reverb != mda[n].reverb) {
|
|
send_3bytes(0xb0 + play[i].channel, 0x5b, mda[n].reverb);
|
|
}
|
|
if(play[i].chorus != mda[n].chorus) {
|
|
send_3bytes(0xb0 + play[i].channel, 0x5d, mda[n].chorus);
|
|
}
|
|
if(play[i].pan != mda[n].pan) {
|
|
send_3bytes(0xb0 + play[i].channel, 0x0a, mda[n].pan);
|
|
}
|
|
}
|
|
play[i].timbre = n;
|
|
play[i].level = mda[n].level;
|
|
play[i].reverb = mda[n].reverb;
|
|
play[i].chorus = mda[n].chorus;
|
|
play[i].key_shift = mda[n].key_shift;
|
|
play[i].pan = mda[n].pan;
|
|
play[i].velocity = 120;
|
|
} else if(d0 == 0xf9) {
|
|
play[i].velocity = next_mml(i);
|
|
} else if(d0 == 0xfc) {
|
|
d1 = next_mml(i);
|
|
if(d1 > 127) {
|
|
d1 = 256 - d1;
|
|
d1 = 0x40 - (d1 > 63 ? 63 : d1);
|
|
} else {
|
|
d1 = 0x40 + (d1 > 63 ? 63 : d1);
|
|
}
|
|
send_3bytes(0xb0 + play[i].channel, 0x65, 0x00);
|
|
send_3bytes(0xb0 + play[i].channel, 0x64, 0x01);
|
|
send_3bytes(0xb0 + play[i].channel, 0x06, d1);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
bool MAKO::load_mml(int page)
|
|
{
|
|
// データ読み込み
|
|
DRI* dri = new DRI();
|
|
int size;
|
|
uint8* data = dri->load(amus, page, &size);
|
|
if(data == NULL) {
|
|
delete dri;
|
|
return false;
|
|
}
|
|
|
|
// FM音源データの判定
|
|
int p, d0, d1, d2;
|
|
|
|
p = data[0] + 1;
|
|
if(data[p] != 0x0f || (data[p + 1] + data[p + 2] + data[p + 3] + data[p + 4] + data[p + 5]) != 0) {
|
|
free(data);
|
|
delete dri;
|
|
return false;
|
|
}
|
|
|
|
// MML部 読み込み&変換
|
|
for(int i = 0; i < 9; i++) {
|
|
p = 4 * (i + 1);
|
|
int block_offset_top = data[p++];
|
|
block_offset_top |= data[p++] << 8;
|
|
int body_addr = 0;
|
|
mml[i].addr = 0;
|
|
|
|
if(block_offset_top) {
|
|
// ブロックの探索
|
|
int last_block = 0;
|
|
p = block_offset_top;
|
|
d0 = data[p++];
|
|
d1 = data[p++];
|
|
while(d1 != 0xff) {
|
|
last_block++;
|
|
d0 = data[p++];
|
|
d1 = data[p++];
|
|
}
|
|
int return_block = d0;
|
|
|
|
uint16 base_octave = 4, current_octave = 4;
|
|
uint16 default_time = 48;
|
|
uint16 gate_step = 7, gate_time = 256;
|
|
uint16 time, on_time, off_time;
|
|
uint16 note;
|
|
|
|
for(int j = 0; j < last_block; j++) {
|
|
if(j == return_block) {
|
|
body_addr = mml[i].addr;
|
|
}
|
|
p = block_offset_top + 2 * j;
|
|
int block_offset = data[p++];
|
|
block_offset |= data[p++] << 8;
|
|
p = block_offset;
|
|
|
|
while((d0 = data[p++]) != 0xff) {
|
|
if((0x00 <= d0 && d0 <= 0x0c) || (0x0d <= d0 && d0 <= 0x19) || (0x80 <= d0 && d0 <=0x8c)) {
|
|
if(0x00 <= d0 && d0 <= 0x0c) {
|
|
time = data[p++];
|
|
note = d0;
|
|
} else if(0x0d <= d0 && d0 <= 0x19) {
|
|
time = data[p++];
|
|
time |= data[p++] << 8;
|
|
note = d0 - 0x0d;
|
|
} else {
|
|
time = default_time;
|
|
note = d0 - 0x80;
|
|
}
|
|
if((d0 = data[p]) == 0xe9) {
|
|
on_time = time;
|
|
off_time = 0;
|
|
p++;
|
|
} else {
|
|
if(gate_time != 256) {
|
|
if(time > gate_time) {
|
|
on_time = time - gate_time;
|
|
off_time = gate_time;
|
|
} else {
|
|
on_time = 1;
|
|
off_time = time - 1;
|
|
}
|
|
} else {
|
|
if(time == 1) {
|
|
on_time = 1;
|
|
off_time = 0;
|
|
} else if(gate_step == 8) {
|
|
on_time = time -1 ;
|
|
off_time = 1;
|
|
} else if(time < 8) {
|
|
on_time = 1;
|
|
off_time = time - 1;
|
|
} else {
|
|
on_time = (time >> 3) * gate_step;
|
|
off_time = time - on_time;
|
|
}
|
|
}
|
|
}
|
|
if(note == 0) {
|
|
off_time = on_time + off_time;
|
|
on_time = 0;
|
|
}
|
|
if(on_time != 0) {
|
|
next_mml(i) = (note - 1) + 12 * (current_octave + 1);
|
|
next_mml(i) = on_time & 0xff;
|
|
next_mml(i) = on_time >> 8;
|
|
}
|
|
next_mml(i) = 0x80;
|
|
next_mml(i) = off_time & 0xff;
|
|
next_mml(i) = off_time >> 8;
|
|
if(current_octave != base_octave) {
|
|
current_octave = base_octave;
|
|
}
|
|
} else if(d0 == 0xe0 || d0 == 0xe1 || d0 == 0xeb || d0 == 0xf5 || d0 == 0xf9 || d0 == 0xfc) {
|
|
next_mml(i) = d0;
|
|
next_mml(i) = data[p++];
|
|
} else if(d0 == 0xea) {
|
|
gate_time = data[p++];
|
|
} else if(d0 == 0xec) {
|
|
next_mml(i) = d0;
|
|
} else if(d0 == 0xee) {
|
|
current_octave = ++base_octave;
|
|
} else if(d0 == 0xef) {
|
|
current_octave = --base_octave;
|
|
} else if(d0 == 0xf0) {
|
|
current_octave = base_octave = data[p++];
|
|
} else if(d0 == 0xf2) {
|
|
gate_step = data[p++] + 1;
|
|
gate_time = 256;
|
|
} else if(d0 == 0xf3) {
|
|
d1 = data[p++];
|
|
if(d1 >= 0x80) {
|
|
d2 = data[p++];
|
|
default_time = ((d1 - 0x80) << 8) | d2;
|
|
} else {
|
|
default_time = d1;
|
|
}
|
|
} else if(d0 == 0xf4) {
|
|
tempo = data[p++];
|
|
} else if(d0 == 0xf7) {
|
|
current_octave--;
|
|
} else if(d0 == 0xf8) {
|
|
current_octave++;
|
|
} else if(d0 == 0xe9) {
|
|
; // Tie Command
|
|
} else if(d0 == 0xe5 || d0 == 0xf1 || d0 == 0xfa || d0 == 0xfd) {
|
|
p++;
|
|
} else if(d0 == 0xf6 || d0 == 0xfb) {
|
|
p += 2;
|
|
} else if(d0 == 0xe4 || d0 == 0xfe) {
|
|
p += 3;
|
|
} else if(d0 == 0xe6 || d0 == 0xe7) {
|
|
p += 8;
|
|
} else if(d0 == 0xe8) {
|
|
p += 10;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
next_mml(i) = 0xff;
|
|
next_mml(i) = (body_addr >> 0) & 0xff;
|
|
next_mml(i) = (body_addr >> 8) & 0xff;
|
|
next_mml(i) = (body_addr >> 16) & 0xff;
|
|
}
|
|
free(data);
|
|
delete dri;
|
|
return true;
|
|
}
|
|
|
|
void MAKO::load_mda(int page)
|
|
{
|
|
// 未設定時の音色設定 (Piano, Acoustic Bass Drum)
|
|
for(int i = 0; i < 256 + 3; i++) {
|
|
mda[i].bank_select = 0;
|
|
mda[i].program_change = 0;
|
|
mda[i].level = 100;
|
|
mda[i].reverb = 40;
|
|
mda[i].chorus = 40;
|
|
mda[i].key_shift = 64;
|
|
mda[i].pan = 64;
|
|
}
|
|
for(int i = 0; i < 8; i++) {
|
|
for(int j = 0; j < 128; j++) {
|
|
drum_map[i][j] = 35;
|
|
}
|
|
}
|
|
tempo_dif = 0x40;
|
|
|
|
// MDAデータの読み込み
|
|
_TCHAR path[16];
|
|
_tcscpy_s(path, 16, amus);
|
|
int p = _tcslen(path);
|
|
path[p - 3] = _T('M');
|
|
path[p - 2] = _T('D');
|
|
path[p - 1] = _T('A');
|
|
|
|
DRI* dri = new DRI();
|
|
int size;
|
|
uint8* data = NULL;
|
|
if((data = dri->load(path, page, &size)) == NULL) {
|
|
data = dri->load_mda(nact->crc32, page, &size);
|
|
}
|
|
|
|
if(data) {
|
|
tempo_dif = data[7];
|
|
int map_wide = data[24];
|
|
int inst_num = data[25];
|
|
int drum_format = data[26];
|
|
|
|
// SSGパートの音色設定
|
|
for(int i = 0; i < 3; i++) {
|
|
uint8* buf = &data[map_wide * i + 27];
|
|
mda[i + 256].bank_select = buf[0];
|
|
mda[i + 256].program_change = buf[1];
|
|
mda[i + 256].level = buf[2];
|
|
mda[i + 256].reverb = buf[3];
|
|
mda[i + 256].chorus = buf[4];
|
|
mda[i + 256].key_shift = buf[5];
|
|
mda[i + 256].pan = buf[6];
|
|
}
|
|
|
|
// 通常の音色設定
|
|
for(int i = 0; i < inst_num; i++) {
|
|
uint8* buf = &data[27 + map_wide * 3 + (map_wide + 1) * i];
|
|
int n = buf[0];
|
|
mda[n].bank_select = buf[1];
|
|
mda[n].program_change = buf[2];
|
|
mda[n].level = buf[3];
|
|
mda[n].reverb = buf[4];
|
|
mda[n].chorus = buf[5];
|
|
mda[n].key_shift = buf[6];
|
|
mda[n].pan = buf[7];
|
|
}
|
|
|
|
// ドラムパートの音色設定
|
|
if(drum_format) {
|
|
uint8* buf = &data[27 + map_wide * 3 + (map_wide + 1) * inst_num];
|
|
int drum_num = buf[0];
|
|
for(int i = 0; i < drum_num; i++) {
|
|
int d = buf[i * 3 + 1];
|
|
int t = buf[i * 3 + 2];
|
|
drum_map[d][t + 12] = buf[i * 3 + 3];
|
|
}
|
|
}
|
|
free(data);
|
|
}
|
|
delete dri;
|
|
}
|
|
|