#include "test.h" #include "fluidsynth.h" #include "utils/fluid_sys.h" #include "synth/fluid_event.h" static fluid_sequencer_t *sequencer; static short synthSeqID, mySeqID; static void sendnoteon(int chan, short key, short velocity, unsigned int time) { fluid_event_t *evt = new_fluid_event(); fluid_event_set_source(evt, -1); fluid_event_set_dest(evt, synthSeqID); fluid_event_noteon(evt, chan, key, velocity); TEST_SUCCESS(fluid_sequencer_send_at(sequencer, evt, time, 0)); delete_fluid_event(evt); } static void sendpc(int chan, short val, unsigned int time) { fluid_event_t *evt = new_fluid_event(); fluid_event_set_source(evt, -1); fluid_event_set_dest(evt, synthSeqID); fluid_event_program_change(evt, chan, val); TEST_SUCCESS(fluid_sequencer_send_at(sequencer, evt, time, 0)); delete_fluid_event(evt); } static void schedule_next_callback(unsigned int time) { fluid_event_t *evt = new_fluid_event(); fluid_event_set_source(evt, -1); fluid_event_set_dest(evt, mySeqID); fluid_event_timer(evt, NULL); TEST_SUCCESS(fluid_sequencer_send_at(sequencer, evt, time, 0)); delete_fluid_event(evt); } static const unsigned int expected_callback_times[] = { 0, 0, 120, 120, 240, 240, 360, 360, 480, 720, 840, 840, 960, 960, 1080, 1080, 1200, 1440, 1560, 1560, 1680, 1680, 1800, 1800, 1920, 2160, 2280, 2280, 2400, 2400, 2520, 2520, 2640, 2880, 3000, 3000, 3120, 3120, 3240, 3240, 3360, 18080 }; static void fake_synth_callback(unsigned int time, fluid_event_t *event, fluid_sequencer_t *seq, void *data) { static int callback_idx = 0; TEST_ASSERT(time == expected_callback_times[callback_idx++]); FLUID_LOG(FLUID_INFO, "synth callback time: %u %u", time, fluid_event_get_time(event)); } static void seq_callback(unsigned int time, fluid_event_t *event, fluid_sequencer_t *seq, void *data) { static int phase = 0; switch(phase) { case 0: sendpc(0, 47, 0); fluid_sequencer_set_time_scale(seq, 320); sendnoteon(0, 47, 60, 0); sendnoteon(0, 47, 0, 120); sendnoteon(0, 47, 90, 120); sendnoteon(0, 47, 0, 240); sendnoteon(0, 47, 110, 240); sendnoteon(0, 47, 0, 360); sendnoteon(0, 47, 127, 360); sendnoteon(0, 47, 0, 480); schedule_next_callback(480 + 240); break; case 1: fluid_sequencer_set_time_scale(seq, 1280 / 2); sendnoteon(0, 47, 60, 0); sendnoteon(0, 47, 0, 120); sendnoteon(0, 47, 80, 120); sendnoteon(0, 47, 0, 240); sendnoteon(0, 47, 90, 240); sendnoteon(0, 47, 0, 360); sendnoteon(0, 47, 100, 360); sendnoteon(0, 47, 0, 480); schedule_next_callback(480 + 240); break; case 2: fluid_sequencer_set_time_scale(seq, 800); sendnoteon(0, 47, 60, 0); sendnoteon(0, 47, 0, 120); sendnoteon(0, 47, 80, 120); sendnoteon(0, 47, 0, 240); sendnoteon(0, 47, 90, 240); sendnoteon(0, 47, 0, 360); sendnoteon(0, 47, 100, 360); sendnoteon(0, 47, 0, 480); schedule_next_callback(480 + 240); break; case 3: fluid_sequencer_set_time_scale(seq, 1000); sendnoteon(0, 47, 60, 0); sendnoteon(0, 47, 0, 120); sendnoteon(0, 47, 80, 120); sendnoteon(0, 47, 0, 240); sendnoteon(0, 47, 90, 240); sendnoteon(0, 47, 0, 360); sendnoteon(0, 47, 100, 360); sendnoteon(0, 47, 0, 480); schedule_next_callback(480 + 240); break; case 4: fluid_sequencer_set_time_scale(seq, 320 / 2); sendnoteon(0, 47, 60, 0); sendnoteon(0, 47, 0, 120); sendnoteon(0, 47, 80, 120); sendnoteon(0, 47, 0, 240); sendnoteon(0, 47, 90, 240); sendnoteon(0, 47, 0, 360); sendnoteon(0, 47, 100, 360); sendnoteon(0, 47, 0, 480); break; case 5: // this is the unregistering event, ignore break; default: TEST_ASSERT(0); } phase++; } // for debug, uncomment below to hear the notes // #define SOUND int main(void) { int i; #ifdef SOUND fluid_settings_t *settings = new_fluid_settings(); fluid_settings_setstr(settings, "audio.driver", "alsa"); fluid_synth_t *synth = new_fluid_synth(settings); TEST_SUCCESS(fluid_synth_sfload(synth, TEST_SOUNDFONT, 1)); #endif sequencer = new_fluid_sequencer2(0); TEST_ASSERT(sequencer != NULL); #ifdef SOUND synthSeqID = fluid_sequencer_register_fluidsynth(sequencer, synth); #else // register fake synth as first destination synthSeqID = fluid_sequencer_register_client(sequencer, "fake synth", fake_synth_callback, NULL); #endif TEST_SUCCESS(synthSeqID); // register myself as scheduling destination mySeqID = fluid_sequencer_register_client(sequencer, "me", seq_callback, NULL); TEST_SUCCESS(mySeqID); // initialize our absolute date schedule_next_callback(0); #ifdef SOUND fluid_audio_driver_t *adriver = new_fluid_audio_driver(settings, synth); fluid_msleep(100000); delete_fluid_audio_driver(adriver); delete_fluid_synth(synth); delete_fluid_settings(settings); #else for(i = 0; i < 100000; i++) { fluid_sequencer_process(sequencer, i); } #endif delete_fluid_sequencer(sequencer); return EXIT_SUCCESS; }