/** * A general-purpose MIDI library, which is basically a number of convenience * functions which use OSS. These functions have been tested only with * /dev/sequencer2 * * Important! The following 4 files (or symlinks) must be present on your * system: * * /etc/sound/std.o3 * /etc/sound/drums.o3 * /etc/sound/std.sb * /etc/sound/drums.sb * * Tested under Linux 2.4m with OSS/Free on Intel architecture only. * * Author: Adam Buckley, adambuckley@gmx.net * Version: $Id: midi.c,v 1.2 2002/05/23 12:13:55 adam Exp $ */ /** * This source code is copyright (c) 2002 Adam Buckley, . * * This source code 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 source code 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. * * The GNU General Public License can be found at * http://www.gnu.org/licenses/gpl.html */ #ifndef ADAMLIB_MIDI_C #define ADAMLIB_MIDI_C #ifndef TRUE #define TRUE 1 #endif #ifndef FALSE #define FALSE 0 #endif #include #include #include #include #include #include #include // seqbuf_dump // ----------- SEQ_DEFINEBUF(128); int seqfd; int seqbuf_dump_error; void seqbuf_dump() { if(_seqbufptr>0) { seqbuf_dump_error = write(seqfd, _seqbuf, _seqbufptr); if(seqbuf_dump_error == -1) perror("Can't write to MIDI device"); _seqbufptr = 0; } } // Constant definitions // -------------------- // Just send the all notes off message #define ALL_NOTES_OFF_SOFT 0 // Cycle through all notes, setting velocity to 0 // For MIDI drivers which incorrectly implement AllNotesOff #define ALL_NOTES_OFF_HARD 1 // Do we print debug messages int MIDI_C_PRINT_MESSAGES = FALSE; // FM Instrument Loading // --------------------- int sbDev=0; int fmReverb=1; #define FM_INSTR_OPL3 0 #define FM_INSTR_SB 1 #define O3MELODIC "/etc/sound/std.o3" #define O3DRUMS "/etc/sound/drums.o3" #define SBMELODIC "/etc/sound/std.sb" #define SBDRUMS "/etc/sound/drums.sb" int openInsFile(char* file) { int r = open(file, O_RDONLY, 0); if(r==-1) { printf("Could not open FM instrument definition file '%s'\n", file); exit(1); } return r; } // Code taken from 'playmidi-2.4' by Nathan I. Laredo void adjustFm(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(fmReverb) { 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 && fmReverb) { 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; } } } /** * Load instrument definitions into the FM soundcard. * * 'mode' may be either FM_INSTR_OPL3 or FM_INSTR_SB * 'device' is the device number (normally 0) * * Based on code from 'playmidi-2.4' by Nathan I. Laredo */ void fmload(int devNum, int reverb, int mode) { int fmloaded[256]; int sbfd, i, n, voice_size, data_size; char buf[60]; struct sbi_instrument instr; fmReverb = reverb; sbDev = devNum; for(i=0; i<256; i++) fmloaded[i] = 0; srand(getpid()); if(mode==FM_INSTR_OPL3) { voice_size = 60; sbfd = openInsFile(O3MELODIC); } else { voice_size = 52; sbfd = openInsFile(SBMELODIC); } instr.device = sbDev; for(i=0; i<128; i++) { if(read(sbfd, buf, voice_size) != voice_size) { printf("Error in instrument definition file\n"); exit(1); } 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(mode==FM_INSTR_OPL3) sbfd = openInsFile(O3DRUMS); else sbfd = openInsFile(SBDRUMS); for(i=128; i<175; i++) { if(read(sbfd, buf, voice_size) != voice_size) { printf("Error in instrument definition file\n"); exit(1); } 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