From e5b76a21b8fafdfa055ea88cc2f15f59160d7a82 Mon Sep 17 00:00:00 2001 From: Angel Ortega Date: Mon, 17 Mar 2008 11:28:46 +0100 Subject: [PATCH] New function ss_load_sf2_file(), to load an instrument from a SoundFont2 file. --- VERSION | 2 +- ahxm.h | 1 + ss_input.c | 286 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 288 insertions(+), 1 deletion(-) diff --git a/VERSION b/VERSION index c1a4a73..4b67f21 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -#define VERSION "1.0.11" +#define VERSION "1.0.12-dev" diff --git a/ahxm.h b/ahxm.h index c672c41..0b62be0 100644 --- a/ahxm.h +++ b/ahxm.h @@ -316,6 +316,7 @@ struct ss_wave * ss_load_wav_file(const char * file, double loop_start, double loop_end, int first_channel, int skip_channels); int ss_load_pat_file(struct ss_ins * i, const char * file); +int ss_load_sf2_file(struct ss_ins *i, const char *file, const char *iname); /* in ss_eff.c */ diff --git a/ss_input.c b/ss_input.c index a2bc659..b2f131b 100644 --- a/ss_input.c +++ b/ss_input.c @@ -381,3 +381,289 @@ int ss_load_pat_file(struct ss_ins *i, const char *file) fclose(f); return 0; } + + +/* Soundfont support */ + +#define CID(a,b,c,d) (((d)<<24)+((c)<<16)+((b)<<8)+((a))) + +#define CID_RIFF CID('R','I','F','F') +#define CID_LIST CID('L','I','S','T') +#define CID_INFO CID('I','N','F','O') +#define CID_sdta CID('s','d','t','a') +#define CID_snam CID('s','n','a','m') +#define CID_smpl CID('s','m','p','l') +#define CID_pdta CID('p','d','t','a') +#define CID_phdr CID('p','h','d','r') +#define CID_pbag CID('p','b','a','g') +#define CID_pmod CID('p','m','o','d') +#define CID_pgen CID('p','g','e','n') +#define CID_inst CID('i','n','s','t') +#define CID_ibag CID('i','b','a','g') +#define CID_imod CID('i','m','o','d') +#define CID_igen CID('i','g','e','n') +#define CID_shdr CID('s','h','d','r') +#define CID_ifil CID('i','f','i','l') +#define CID_isng CID('i','s','n','g') +#define CID_irom CID('i','r','o','m') +#define CID_iver CID('i','v','e','r') +#define CID_INAM CID('I','N','A','M') +#define CID_IPRD CID('I','P','R','D') +#define CID_ICOP CID('I','C','O','P') +#define CID_sfbk CID('s','f','b','k') +#define CID_ICRD CID('I','C','R','D') +#define CID_IENG CID('I','E','N','G') +#define CID_ICMT CID('I','C','M','T') +#define CID_ISFT CID('I','S','F','T') + +#define MAX_LAYERS 128 + +static int min_notes[MAX_LAYERS]; +static int max_notes[MAX_LAYERS]; +static int sampleids[MAX_LAYERS]; + +#define CALC_END(s,f) (ftell(f) + (s) + ((s) & 1)) + + +int ss_load_sf2_file(struct ss_ins *i, const char *file, const char *iname) +{ + FILE *f; + int n, num; + int cid, fsize, fend; + int sample_offset = 0; + int ibag_s = -1, ibag_e = -1; + int igen_s = -1, igen_e = -1; + char tmp[21]; + int i_notes = 0, i_samples = 0; + + if ((f = libpath_fopen(file, "r")) == NULL) + return -100; + + if ((cid = fget32(f)) != CID_RIFF) + return -101; + + fsize = fget32(f); + fend = CALC_END(fsize, f); + + if ((cid = fget32(f)) != CID_sfbk) + return -102; + + while (ftell(f) < fend) { + int csize, cend; + + cid = fget32(f); + csize = fget32(f); + cend = CALC_END(csize, f); + + switch (cid) { + case CID_LIST: + + cid = fget32(f); + + while (ftell(f) < cend) { + int scid, ssize, send; + + scid = fget32(f); + ssize = fget32(f); + send = CALC_END(ssize, f); + + switch (cid) { + case CID_INFO: + + switch (scid) { + case CID_ifil: + + if (fget16(f) < 2) + return -103; + fget16(f); + break; + + case CID_INAM: + case CID_irom: + case CID_ICRD: + case CID_IENG: + case CID_IPRD: + case CID_ICOP: + case CID_ISFT: + /* misc. data (ignored) */ + break; + } + + fseek(f, send, SEEK_SET); + break; + + case CID_pdta: + + switch (scid) { + case CID_phdr: + /* preset headers */ + break; + + case CID_pbag: + /* preset index list */ + break; + + case CID_pgen: + /* preset generator list */ + break; + + case CID_inst: + /* instrument names */ + num = ssize / 22; + + for (n = 0; n < num; n++) { + int i; + + fread(tmp, 20, 1, f); + tmp[20] = '\0'; + i = fget16(f); + + /* if ibag_s is set and ibag_e isn't, + pick this as the end */ + if (ibag_s != -1 && ibag_e == -1) + ibag_e = i; + + if (iname != NULL) { + if (strcmp(iname, tmp) == 0) + ibag_s = i; + } + else { + printf("[%s]\n", tmp); + } + } + + break; + + case CID_ibag: + + num = ssize / 4; + + for (n = 0; n < num; n++) { + int igen = fget16(f); + fget16(f); + + /* pick start of igen */ + if (n == ibag_s) + igen_s = igen; + + /* pick end of igen */ + if (n == ibag_e) + igen_e = igen; + } + + break; + + case CID_igen: + + num = ssize / 4; + + for (n = 0; n < num; n++) { + int op = fget16(f); + int am = fget16(f); + + if (n >= igen_s && n < igen_e) { + + if (op == 43) { /* keyRange */ + min_notes[i_notes] = am & 0xff; + max_notes[i_notes] = am >> 8; + i_notes++; + } + + if (op == 53) { /* sampleID */ + sampleids[i_samples++] = am; + } + } + } + + break; + + case CID_shdr: + /* sample headers */ + num = ssize / 46; + + for (n = 0; n < num; n++) { + int m; + int start, end; + int loop_start, loop_end; + int sample_rate, base_note; + int sample_type; + + fread(tmp, 20, 1, f); + tmp[20] = '\0'; + + start = fget32(f); + end = fget32(f); + loop_start = fget32(f); + loop_end = fget32(f); + sample_rate = fget32(f); + base_note = fgetc(f); + fgetc(f); /* correction */ + fget16(f); /* sample_link */ + sample_type = fget16(f); + + for (m = 0; m < i_samples; m++) { + if (sampleids[m] == n) { + /* create wave! */ + struct ss_wave *w; + int t; + + w = ss_alloc_wave( + end - start, 1, + sample_rate, -1 + ); + + w->loop_start = loop_start; + w->loop_end = loop_end; + w->base_freq = ss_note_frequency(base_note); + w->min_freq = ss_note_frequency(min_notes[m]); + w->max_freq = ss_note_frequency(max_notes[m]); + + w->bits = 16; + w->sign = 1; + + t = ftell(f); + + fseek(f, sample_offset + (start * 2), SEEK_SET); + + ss_prepare_wave(w); + load_pcm_wave(f, w); + + fseek(f, t, SEEK_SET); + + ss_ins_add_layer(i, w); + } + } + } + + break; + } + + fseek(f, send, SEEK_SET); + break; + + case CID_sdta: + + /* sample info starts here */ + sample_offset = ftell(f); + + fseek(f, send, SEEK_SET); + break; + + default: + /* unknown chunk */ + fseek(f, cend, SEEK_SET); + break; + } + } + + break; + + default: + fseek(f, cend, SEEK_SET); + break; + } + } + + fclose(f); + return 0; +} -- 2.11.4.GIT