ref: d4c74b9d3bd4316a95d5803ed7dec737da94ee8d
dir: /sf2mid.c/
/* adapted from examples */ #define TSF_IMPLEMENTATION #include "tsf.h" #define TML_IMPLEMENTATION #include "tml.h" #include <unistd.h> tsf *ttsf; double T; /* msec */ tml_message* next; enum{ Sampsz = 2 * 2, Delay = 1764, /* 40 ms */ Rate = 44100, }; static int samp(void*, tsf_s16 *stream, int samp) { int chunk; samp *= 2; for(chunk=2048; samp!=0; samp-=chunk){ if(chunk > samp) chunk = samp; T += (1000.0 / Rate) * chunk / 2; for(; next && T >= next->time; next = next->next){ switch(next->type){ case TML_PROGRAM_CHANGE: tsf_channel_set_presetnumber(ttsf, next->channel, next->program, next->channel == 9); break; case TML_NOTE_ON: tsf_channel_note_on(ttsf, next->channel, next->key, next->velocity / 127.0); break; case TML_NOTE_OFF: tsf_channel_note_off(ttsf, next->channel, next->key); break; case TML_PITCH_BEND: tsf_channel_set_pitchwheel(ttsf, next->channel, next->pitch_bend); break; case TML_CONTROL_CHANGE: tsf_channel_midi_control(ttsf, next->channel, next->control, next->control_value); break; } } if(next == NULL) return -1; tsf_render_short(ttsf, stream, chunk, 0); stream += chunk; } return 0; } int main(int argc, char **argv) { FILE *out; char *sf, *mid; tml_message* tml; tsf_s16 obuf[Sampsz * Delay]; sf = NULL; mid = "/fd/0"; out = stdout; if(argc < 2){ fprintf(stderr, "usage: %s SF2BANK [FILE]\n", argv[0]); return 1; } if(argc >= 2) sf = argv[1]; if(argc >= 3) mid = argv[2]; if((tml = tml_load_filename(mid)) == NULL){ fprintf(stderr, "error reading midi file\n"); return 1; } if((ttsf = tsf_load_filename(sf)) == NULL){ fprintf(stderr, "error loading soundfont\n"); return 2; } next = tml; // arm 10th channel for percussion sound bank (128) if available tsf_channel_set_bank_preset(ttsf, 9, 128, -3.0); tsf_set_output(ttsf, TSF_STEREO_UNWEAVED, Rate, 0.0); for(;;){ memset(obuf, 0, sizeof obuf); if(samp(NULL, obuf, Delay) < 0) break; fwrite(obuf, Delay, 4, out); } return 0; }