bool32 start on risign edge, stop on falling edge
None
file MIDI file
combo device
tml_message *TinyMidiLoader = NULL;
tml_message *g_MidiMessage = NULL;
tml_message *g_FirstMidiMessage = NULL;
int ktime = 0;
bool pplay = 0;
FIL fp;
FRESULT res;
const char *fn = "attr_file";
res = f_open(&fp, fn, FA_READ | FA_OPEN_EXISTING);
if (res != FR_OK) {
report_fatfs_error(res, fn);
}
UINT file_size = f_size(&fp);
if (file_size > (4 * 1024 * 1024)) {
LogTextMessage("MIDI file is very large, likely to fail\n");
}
void *file_buffer;
file_buffer = sdram_malloc(file_size);
UINT bytes_read;
res = f_read(&fp, file_buffer, file_size, &bytes_read);
if (res != FR_OK) {
report_fatfs_error(res, fn);
}
f_close(&fp);
if (bytes_read != file_size) {
LogTextMessage("bytes_read (%d) != file_size (%d)", bytes_read, file_size);
}
TinyMidiLoader = tml_load_memory(file_buffer, file_size);
if (!TinyMidiLoader) {
LogTextMessage("Could not load MIDI file\n");
} else {
// LogTextMessage("MIDI file loaded succesfully\n");
}
// Set up the global MidiMessage pointer to the first MIDI message
g_FirstMidiMessage = TinyMidiLoader;
if (inlet_play && !pplay) {
if (!g_MidiMessage) {
// LogTextMessage("start");
ktime = 0;
g_MidiMessage = g_FirstMidiMessage;
}
}
if (!inlet_play && pplay) {
// stop playing
g_MidiMessage = 0;
// send all notes off to all channels
int i;
for (i = 0; i < 16; i++) {
MidiSend3((midi_device_t)attr_device, MIDI_CONTROL_CHANGE | i, 123, 0);
}
// LogTextMessage("stopped");
}
if (ktime & 0x80000000) {
// prevent timer overflow after several days
g_MidiMessage = 0;
ktime = 0;
}
pplay = inlet_play;
ktime++; // current playback time in buffers
float g_Msec = ktime * 0.33333f; // current playback time in milliseconds
// 0.3333ms = 1s/3000Hz
for (; g_MidiMessage && g_Msec >= g_MidiMessage->time;
g_MidiMessage = g_MidiMessage->next) {
switch (g_MidiMessage->type) {
case TML_NOTE_ON: // play a note
MidiSend3((midi_device_t)attr_device, MIDI_NOTE_ON | g_MidiMessage->channel,
g_MidiMessage->key, g_MidiMessage->velocity);
/*
LogTextMessage("note-on : %02x %02x %02x",
g_MidiMessage->channel,
g_MidiMessage->key,
g_MidiMessage->velocity);
*/
break;
case TML_NOTE_OFF: // stop a note
MidiSend3((midi_device_t)attr_device,
MIDI_NOTE_OFF | g_MidiMessage->channel, g_MidiMessage->key,
g_MidiMessage->velocity);
break;
case TML_KEY_PRESSURE:
MidiSend3((midi_device_t)attr_device,
MIDI_POLY_PRESSURE | g_MidiMessage->channel, g_MidiMessage->key,
g_MidiMessage->velocity);
break;
case TML_PITCH_BEND: // pitch wheel modification
MidiSend3((midi_device_t)attr_device,
MIDI_PITCH_BEND | g_MidiMessage->channel,
g_MidiMessage->pitch_bend & 0x7F, g_MidiMessage->pitch_bend >> 7);
break;
case TML_CONTROL_CHANGE: // MIDI controller messages
MidiSend3((midi_device_t)attr_device,
MIDI_CONTROL_CHANGE | g_MidiMessage->channel,
g_MidiMessage->control, g_MidiMessage->control_value);
break;
case TML_PROGRAM_CHANGE:
MidiSend2((midi_device_t)attr_device,
MIDI_PROGRAM_CHANGE | g_MidiMessage->channel,
g_MidiMessage->program);
break;
}
}