|
#include <fluidsynth.h> |
|
#include <unistd.h> |
|
|
|
// global vars have external linkage by default (https://stackoverflow.com/a/4239955/2228912) |
|
static fluid_settings_t *settings; |
|
static fluid_synth_t* synth; |
|
static fluid_audio_driver_t* driver; |
|
|
|
// global constants also have external linkages (https://stackoverflow.com/a/13185812/2228912) |
|
// Key for C4 (middle C) = 60 (key code incremented by one when going a half-tone up) |
|
// int c4 = 60; |
|
static const int G4 = 67; |
|
static const int A4 = 69; |
|
static const int B4 = 71; |
|
static const int C5 = 72; |
|
static const int D5 = 74; |
|
|
|
// midi channel to play notes on (max for midi = 16) |
|
static const int CHANNEL = 0; |
|
|
|
// sleep determines duration (leaves time for note to play) |
|
static const unsigned int DURATION = 500 * 1000; // 500ms |
|
|
|
// how hard key was struck (max = 127) |
|
static const int VELOCITY = 127; |
|
|
|
/* free() do nothing when called on NULL pointers */ |
|
static void clean_up() { |
|
// driver must be the first to delete (depends on others) => reverse order of init. |
|
delete_fluid_audio_driver(driver); |
|
delete_fluid_synth(synth); |
|
delete_fluid_settings(settings); |
|
} |
|
|
|
static void play_note(int note) { |
|
fluid_synth_noteon(synth, CHANNEL, note, VELOCITY); |
|
usleep(DURATION); |
|
fluid_synth_noteoff(synth, CHANNEL, note); |
|
} |
|
|
|
/** |
|
* Plays first few notes from "Frere Jaques" using Fluidsynth C API |
|
* Frere Jaques (Key of G): https://www.true-piano-lessons.com/frere-jacques.html |
|
* Reference: https://www.fluidsynth.org/api/UsageGuide.html |
|
* |
|
* Build & run: |
|
* $ gcc -lfluidsynth freres_jaques.c -o app |
|
* $ ./app /usr/share/soundfonts/FluidR3_GM.sf2 |
|
*/ |
|
int main(int argc, char* argv[]) { |
|
if (argc != 2) { |
|
printf("USAGE: %s SF2-FILE\n", argv[0]); |
|
return 1; |
|
} |
|
|
|
// settings |
|
settings = new_fluid_settings(); |
|
if (settings == NULL) { |
|
printf("Failed to create settings\n"); |
|
clean_up(); |
|
return 1; |
|
} |
|
|
|
// synthesizer |
|
synth = new_fluid_synth(settings); |
|
if (synth == NULL) { |
|
printf("Failed to create synthesizer\n"); |
|
clean_up(); |
|
return 1; |
|
} |
|
|
|
// soundfont |
|
const char* path_sf2 = argv[1]; |
|
int id_soundfont = fluid_synth_sfload(synth, path_sf2, 1); |
|
if (id_soundfont == FLUID_FAILED) { |
|
printf("Failed to load soundfont\n"); |
|
clean_up(); |
|
return 1; |
|
} |
|
|
|
// audio driver: alsa, pulseaudio, jack... (must be last one to create) |
|
// starts playing audio (in separate thread) once driver created |
|
driver = new_fluid_audio_driver(settings, synth); |
|
if (driver == NULL) { |
|
printf("Failed to create audio driver\n"); |
|
clean_up(); |
|
return 1; |
|
} |
|
|
|
// play first notes from "Frere Jaques" |
|
for (size_t i = 0; i < 2; i++) { |
|
play_note(G4); |
|
play_note(A4); |
|
play_note(B4); |
|
play_note(G4); |
|
} |
|
|
|
for (size_t i = 0; i < 2; i++) { |
|
play_note(B4); |
|
play_note(C5); |
|
play_note(D5); |
|
usleep(DURATION); |
|
} |
|
|
|
clean_up(); |
|
|
|
return 0; |
|
} |