/*================================================================ * sf2text -- print soundfont layer information * * Copyright (C) 1996,1997 Takashi Iwai * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. *================================================================*/ #ifdef HAVE_CONFIG_H #include "config.h" #endif /* HAVE_CONFIG_H */ #include #include #include #include #include "timidity.h" #include "common.h" #include "sffile.h" #include "sfitem.h" #include "sflayer.h" #include "controls.h" #include "instrum.h" #include "playmidi.h" #include "output.h" #include "wrd.h" static SFInfo sfinfo; void print_soundfont(FILE *fp, SFInfo *sf); static void print_name(FILE *fp, char *str); static void print_layers(FILE *fp, SFInfo *sf, SFHeader *hdr); static void print_amount(FILE *fp, SFInfo *sf, SFGenRec *gen); /*ARGSUSED*/ static int null_cmsg(int type, int verbosity_level, char *fmt, ...){return 0;} static void null_proc(){} static ControlMode null_control_mode = { "", 0, 1,0,0, NULL, null_proc, NULL, NULL, null_cmsg, null_proc }; static PlayMode null_play_mode = { 8000, PE_MONO, 0, -1, {0,0,0,0,0}, "", 0, "", NULL, NULL, null_proc, NULL, NULL, null_proc, NULL, NULL }; /*ARGSUSED*/ static int null_wrdt_open(char *wrdt_opts) { return 0; } /*ARGSUSED*/ static void null_wrdt_apply(int cmd, int argc, int args[]) { } static void null_wrdt_update_events(void) { } static void null_wrdt_end(void) { } static void null_wrdt_close(void) { } static WRDTracer null_wrdt_mode = { "No WRD trace", '-', 0, null_wrdt_open, null_wrdt_apply, null_wrdt_update_events, NULL, null_wrdt_end, null_wrdt_close }; PlayMode *play_mode = &null_play_mode; ControlMode *ctl = &null_control_mode; WRDTracer *wrdt = &null_wrdt_mode; int progbase = 0; extern struct URL_module URL_module_file; #ifdef SUPPORT_SOCKET extern struct URL_module URL_module_http; extern struct URL_module URL_module_ftp; extern struct URL_module URL_module_news; #endif /* SUPPORT_SOCKET */ int main(int argc, char **argv) { struct timidity_file *fd; FILE *fout; if (argc < 2) { fprintf(stderr, "no file is given\n"); fprintf(stderr, "usage: sf2text soundfont [outputfile]\n"); exit(1); } url_add_modules( &URL_module_file, #ifdef SUPPORT_SOCKET &URL_module_http, &URL_module_ftp, &URL_module_news, #endif /* SUPPORT_SOCKET */ NULL); if ((fd = open_file(argv[1], 1, 0)) == NULL) { fprintf(stderr, "can't open file %s\n", argv[1]); exit(1); } if (load_soundfont(&sfinfo, fd) < 0) exit(1); close_file(fd); if (argc < 3) fout = stdout; else { if ((fout = fopen(argv[2], "w")) == NULL) { fprintf(stderr, "can't open file %s\n", argv[2]); exit(1); } } print_soundfont(fout, &sfinfo); return 0; } void print_soundfont(FILE *fp, SFInfo *sf) { int i; SFPresetHdr *preset; SFInstHdr *inst; SFSampleInfo *sp; fprintf(fp, "(Name "); print_name(fp, sf->sf_name); fprintf(fp, ")\n"); fprintf(fp, "(SoundFont %d %d)\n", sf->version, sf->minorversion); fprintf(fp, "(SamplePos %ld %ld)\n", (long)sf->samplepos, (long)sf->samplesize); fprintf(fp, "(InfoPos %ld %ld)\n", sf->infopos, sf->infosize); fprintf(fp, "(Presets %d (\n", sf->npresets); for (preset = sf->preset, i = 0; i < sf->npresets; preset++, i++) { fprintf(fp, " ("); fprintf(fp, "%d ", i); print_name(fp, preset->hdr.name); fprintf(fp, " (preset %d) (bank %d) (\n", preset->preset, preset->bank); print_layers(fp, sf, &preset->hdr); fprintf(fp, " ))\n"); } fprintf(fp, " ))\n"); fprintf(fp, "(Instruments %d (\n", sf->ninsts); for (inst = sf->inst, i = 0; i < sf->ninsts; inst++, i++) { fprintf(fp, " ("); fprintf(fp, "%d ", i); print_name(fp, inst->hdr.name); fprintf(fp, " (\n"); print_layers(fp, sf, &inst->hdr); fprintf(fp, " ))\n"); } fprintf(fp, " ))\n"); fprintf(fp, "(SampleInfo %d (\n", sf->nsamples); for (sp = sf->sample, i = 0; i < sf->nsamples; sp++, i++) { fprintf(fp, " (%d ", i); print_name(fp, sp->name); fprintf(fp, " (0x%lx 0x%lx) (0x%lx 0x%lx)", (long)sp->startsample, (long)sp->endsample, (long)sp->startloop, (long)sp->endloop); if (sf->version == 2) { fprintf(fp, "\n (%ld %d %d %d %d)", (long)sp->samplerate, sp->originalPitch, sp->pitchCorrection, sp->samplelink, sp->sampletype); } fprintf(fp, ")\n"); } fprintf(fp, " ))\n"); } /* print string value. escape or convert the letter to octet if necessary. */ static void print_name(FILE *fp, char *str) { char *p; putc('"', fp); for (p = str; *p; p++) { if (!isprint((int)*p)) fprintf(fp, "\\%03o", *p); else if (*p == '"') fprintf(fp, "\\\""); else putc(*p, fp); } putc('"', fp); } /* print layered list */ static void print_layers(FILE *fp, SFInfo *sf, SFHeader *hdr) { SFGenLayer *lay = hdr->layer; int j, k; for (j = 0; j < hdr->nlayers; lay++, j++) { if (lay->nlists == 0) continue; fprintf(fp, " (layer\n"); for (k = 0; k < lay->nlists; k++) { print_amount(fp, sf, &lay->list[k]); if (k == lay->nlists-1) fprintf(fp, ")\n"); else fprintf(fp, "\n"); } } } static int abscent_to_mHz(int abscents) { return (int)(8176.0 * pow(2.0, (double)abscents / 1200.0)); } int abscent_to_Hz(int abscents) { return (int)(8.176 * pow(2.0, (double)abscents / 1200.0)); } static int timecent_to_msec(int timecent) { return (int)(1000 * pow(2.0, (double)timecent / 1200.0)); } /* print a layer item together with optional info */ static void print_amount(FILE *fp, SFInfo *sf, SFGenRec *gen) { LayerItem *item = &layer_items[gen->oper]; int amount; fprintf(fp, " (%s %d", sf_gen_text[gen->oper], gen->amount); if (sf->version == 1) amount = sbk_to_sf2(gen->oper, gen->amount); else amount = gen->amount; switch (item->type) { case T_NOP: case T_NOCONV: case T_OFFSET: case T_HI_OFF: case T_SCALE: fprintf(fp, " "); if (gen->oper == SF_sampleId) print_name(fp, sf->sample[amount].name); else if (gen->oper == SF_instrument) print_name(fp, sf->inst[amount].hdr.name); else fprintf(fp, "%d", amount); break; case T_RANGE: fprintf(fp, " (%d %d)", LOWNUM(amount), HIGHNUM(amount)); break; case T_FILTERQ: case T_ATTEN: case T_TREMOLO: case T_VOLSUST: fprintf(fp, " %d cB", amount); break; case T_MODSUST: fprintf(fp, " %g %%", (double)amount/10.0); break; case T_CUTOFF: fprintf(fp, " %d Hz", abscent_to_Hz(amount)); break; case T_FREQ: fprintf(fp, " %d mHz", abscent_to_mHz(amount)); break; case T_TIME: fprintf(fp, " %d msec", timecent_to_msec(amount)); break; case T_TENPCT: case T_PANPOS: fprintf(fp, " %g %%", (double)amount / 10.0); break; case T_PSHIFT: case T_CSHIFT: fprintf(fp, " %g semitone", (double)amount / 100); break; } fprintf(fp, ")"); }