📄 patchload.c
字号:
/************************************************************************ patchload.c -- loads patches for playmidi package Some of this code was adapted from code written by Hannu Solovainen Copyright (C) 1994-1996 Nathan I. Laredo This program is modifiable/redistributable under the terms of the GNU General Public Licence. 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. Send your comments and all your spare pocket change to laredo@gnu.ai.mit.edu (Nathan Laredo) or to PSC 1, BOX 709, 2401 Kelly Drive, Lackland AFB, TX 78236-5128, USA. *************************************************************************//* edited by Peter Kutak *//* email : kutak@stonline.sk */#if defined(linux) || defined(__FreeBSD__)#include "playmidi.h"#ifdef linux#include <linux/ultrasound.h>#else#include <machine/ultrasound.h>#endif#include <sys/stat.h>#include <fcntl.h>#include <unistd.h>#include "gmvoices.h"SEQ_USE_EXTBUF();extern int play_gus, play_sb, play_ext, playing, verbose, force8bit;extern int reverb, fmloaded[256], patchloaded[256];extern int gus_dev, sb_dev, ext_dev, seqfd, wantopl3;extern struct synth_info card_info[MAX_CARDS];static int use8bit = 0;struct pat_header { char magic[12]; char version[10]; char description[60]; unsigned char instruments; char voices; char channels; unsigned short nr_waveforms; unsigned short master_volume; unsigned int data_size;};struct sample_header { char name[7]; unsigned char fractions; int len; int loop_start; int loop_end; unsigned short base_freq; int low_note; int high_note; int base_note; short detune; unsigned char panning; unsigned char envelope_rate[6]; unsigned char envelope_offset[6]; unsigned char tremolo_sweep; unsigned char tremolo_rate; unsigned char tremolo_depth; unsigned char vibrato_sweep; unsigned char vibrato_rate; unsigned char vibrato_depth; char modes; short scale_frequency; unsigned short scale_factor;};struct patch_info *patch;int spaceleft, totalspace;void gus_reload_8_bit();void gus_load(pgm)int pgm;{ int i, j, patfd, offset; struct pat_header header; struct sample_header sample; char buf[256], name[256]; struct stat info; if (pgm < 0) { use8bit = force8bit; GUS_NUMVOICES(gus_dev, (card_info[gus_dev].nr_voices = 32)); SEQ_DUMPBUF(); for (i = 0; i < 256; i++) patchloaded[i] = 0; if (ioctl(seqfd, SNDCTL_SEQ_RESETSAMPLES, &gus_dev) == -1) { /* error: should quit */ } spaceleft = gus_dev; ioctl(seqfd, SNDCTL_SYNTH_MEMAVL, &spaceleft); totalspace = spaceleft; } if (patchloaded[pgm] < 0) return; if (patchloaded[pgm] == 1) return; if (gmvoice[pgm] == NULL) { patchloaded[pgm] = -1; return; } sprintf(name, PATCH_PATH1 "/%s.pat", gmvoice[pgm]); if (stat(name, &info) == -1) { sprintf(name, PATCH_PATH2 "/%s.pat", gmvoice[pgm]); if (stat(name, &info) == -1) return; } if ((patfd = open(name, O_RDONLY, 0)) == -1) return; if (spaceleft < info.st_size) { if (!use8bit) gus_reload_8_bit(); if (use8bit) if (spaceleft < info.st_size / 2) { close(patfd); patchloaded[pgm] = -1; /* no space for patch */ return; } } if (read(patfd, buf, 0xef) != 0xef) { close(patfd); return; } memcpy((char *) &header, buf, sizeof(header)); if (strncmp(header.magic, "GF1PATCH110", 12)) { close(patfd); return; } if (strncmp(header.version, "ID#000002", 10)) { close(patfd); return; } header.nr_waveforms = *(unsigned short *) &buf[85]; header.master_volume = *(unsigned short *) &buf[87]; offset = 0xef; for (i = 0; i < header.nr_waveforms; i++) { if (lseek(patfd, offset, 0) == -1) { close(patfd); return; } if (read(patfd, &buf, sizeof(sample)) != sizeof(sample)) { close(patfd); return; } memcpy((char *) &sample, buf, sizeof(sample)); /* * Since some fields of the patch record are not 32bit aligned, we must * handle them specially. */ sample.low_note = *(int *) &buf[22]; sample.high_note = *(int *) &buf[26]; sample.base_note = *(int *) &buf[30]; sample.detune = *(short *) &buf[34]; sample.panning = (unsigned char) buf[36]; memcpy(sample.envelope_rate, &buf[37], 6); memcpy(sample.envelope_offset, &buf[43], 6); sample.tremolo_sweep = (unsigned char) buf[49]; sample.tremolo_rate = (unsigned char) buf[50]; sample.tremolo_depth = (unsigned char) buf[51]; sample.vibrato_sweep = (unsigned char) buf[52]; sample.vibrato_rate = (unsigned char) buf[53]; sample.vibrato_depth = (unsigned char) buf[54]; sample.modes = (unsigned char) buf[55]; sample.scale_frequency = *(short *) &buf[56]; sample.scale_factor = *(unsigned short *) &buf[58]; offset = offset + 96; patch = (struct patch_info *) malloc(sizeof(*patch) + sample.len); if (patch == NULL) { close(patfd); return; } patch->key = GUS_PATCH; patch->device_no = gus_dev; patch->instr_no = pgm; patch->mode = sample.modes | WAVE_TREMOLO | WAVE_VIBRATO | WAVE_SCALE; patch->len = (use8bit ? sample.len / 2 : sample.len); patch->loop_start = (use8bit ? sample.loop_start / 2 : sample.loop_start); patch->loop_end = (use8bit ? sample.loop_end / 2 : sample.loop_end); patch->base_note = sample.base_note; patch->high_note = sample.high_note; patch->low_note = sample.low_note; patch->base_freq = sample.base_freq; patch->detuning = sample.detune; patch->panning = (sample.panning - 7) * 16; memcpy(patch->env_rate, sample.envelope_rate, 6); for (j = 0; j < 6; j++) /* tone things down slightly */ patch->env_offset[j] = (736 * sample.envelope_offset[j] + 384) / 768; if (reverb) if (pgm < 120) patch->env_rate[3] = (2 << 6) | (12 - (reverb >> 4)); else if (pgm > 127) patch->env_rate[1] = (3 << 6) | (63 - (reverb >> 1)); patch->tremolo_sweep = sample.tremolo_sweep; patch->tremolo_rate = sample.tremolo_rate; patch->tremolo_depth = sample.tremolo_depth; patch->vibrato_sweep = sample.vibrato_sweep; patch->vibrato_rate = sample.vibrato_rate; patch->vibrato_depth = sample.vibrato_depth; patch->scale_frequency = sample.scale_frequency; patch->scale_factor = sample.scale_factor; patch->volume = header.master_volume; if (lseek(patfd, offset, 0) == -1) { close(patfd); return; } if (read(patfd, patch->data, sample.len) != sample.len) { close(patfd); return; } if (patch->mode & WAVE_16_BITS && use8bit) { patch->mode &= ~WAVE_16_BITS; /* cut out every other byte to make 8-bit data from 16-bit */ for (j = 0; j < patch->len; j++) patch->data[j] = patch->data[1 + j * 2]; } SEQ_WRPATCH(patch, sizeof(*patch) + patch->len); free(patch); offset = offset + sample.len; } close(patfd); spaceleft = gus_dev; ioctl(seqfd, SNDCTL_SYNTH_MEMAVL, &spaceleft); patchloaded[pgm] = 1; return;}void gus_reload_8_bit(){ int i; if (ioctl(seqfd, SNDCTL_SEQ_RESETSAMPLES, &gus_dev) == -1) { /* error: should quit */ } spaceleft = gus_dev; ioctl(seqfd, SNDCTL_SYNTH_MEMAVL, &spaceleft); totalspace = spaceleft; use8bit = 1; for (i = 0; i < 256; i++) if (patchloaded[i] > 0) { patchloaded[i] = 0; gus_load(i); }}void adjustfm(buf, key)char *buf;int key;{ unsigned char pan = ((rand() % 3) + 1) << 4; if (key == FM_PATCH) { buf[39] &= 0xc0; if (buf[46] & 1) buf[38] &= 0xc0; buf[46] = (buf[46] & 0xcf) | pan; if (reverb) { unsigned val; val = buf[43] & 0x0f; if (val > 0) val--; buf[43] = (buf[43] & 0xf0) | val; } } else { int mode; if (buf[46] & 1) mode = 2; else mode = 0; if (buf[57] & 1) mode++; buf[50] &= 0xc0; if (mode == 3) buf[49] &= 0xc0; if (mode == 1) buf[39] &= 0xc0; if (mode == 2 || mode == 3) buf[38] &= 0xc0; buf[46] = (buf[46] & 0xcf) | pan; buf[57] = (buf[57] & 0xcf) | pan; if (mode == 1 && reverb) { unsigned val; val = buf[43] & 0x0f; if (val > 0) val--; buf[43] = (buf[43] & 0xf0) | val; val = buf[54] & 0x0f; if (val > 0) val--; buf[54] = (buf[54] & 0xf0) | val; } }}void loadfm(){ int sbfd, i, n, voice_size, data_size; char buf[60]; struct sbi_instrument instr; for (i = 0; i < 256; i++) fmloaded[i] = 0; srand(getpid()); if (wantopl3) { voice_size = 60; sbfd = open(O3MELODIC, O_RDONLY, 0); } else { voice_size = 52; sbfd = open(SBMELODIC, O_RDONLY, 0); } if (sbfd == -1) { /* error: should quit */ } instr.device = sb_dev; for (i = 0; i < 128; i++) { if (read(sbfd, buf, voice_size) != voice_size) { /* error: should quit */ } instr.channel = i; if (strncmp(buf, "4OP", 3) == 0) { instr.key = OPL3_PATCH; data_size = 22; } else { instr.key = FM_PATCH; data_size = 11; } fmloaded[i] = instr.key; adjustfm(buf, instr.key); for (n = 0; n < 32; n++) instr.operators[n] = (n < data_size) ? buf[36 + n] : 0; SEQ_WRPATCH(&instr, sizeof(instr)); } close(sbfd); if (wantopl3) sbfd = open(O3DRUMS, O_RDONLY, 0); else sbfd = open(SBDRUMS, O_RDONLY, 0); for (i = 128; i < 175; i++) { if (read(sbfd, buf, voice_size) != voice_size) { /* error: should quit */ } instr.channel = i; if (strncmp(buf, "4OP", 3) == 0) { instr.key = OPL3_PATCH; data_size = 22; } else { instr.key = FM_PATCH; data_size = 11; } fmloaded[i] = instr.key; adjustfm(buf, instr.key); for (n = 0; n < 32; n++) instr.operators[n] = (n < data_size) ? buf[n + 36] : 0; SEQ_WRPATCH(&instr, sizeof(instr)); } close(sbfd);}#endif /* linux || FreeBSD */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -