diff options
Diffstat (limited to 'libkmid/midimapper.cc')
-rw-r--r-- | libkmid/midimapper.cc | 456 |
1 files changed, 456 insertions, 0 deletions
diff --git a/libkmid/midimapper.cc b/libkmid/midimapper.cc new file mode 100644 index 000000000..0b8022b8e --- /dev/null +++ b/libkmid/midimapper.cc @@ -0,0 +1,456 @@ +/************************************************************************** + + midimapper.cc - The midi mapper object + This file is part of LibKMid 0.9.5 + Copyright (C) 1997,98,99,2000 Antonio Larrosa Jimenez + LibKMid's homepage : http://www.arrakis.es/~rlarrosa/libkmid.html + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Library General Public + License as published by the Free Software Foundation; either + version 2 of the License, or (at your option) any later version. + + This library 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 + Library General Public License for more details. + + You should have received a copy of the GNU Library General Public License + along with this library; see the file COPYING.LIB. If not, write to + the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + Boston, MA 02110-1301, USA. + + Send comments and bug fixes to Antonio Larrosa <larrosa@kde.org> + +***************************************************************************/ +#include "midimapper.h" +#include <stdio.h> +#include <string.h> +#include <stdlib.h> +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +MidiMapper::MidiMapper(const char *name) +{ + _ok=1; + keymaps=NULL; + _filename=NULL; + mapPitchBender=0; + mapExpressionToVolumeEvents=0; + if ((name==NULL)||(name[0]==0)) + { + deallocateMaps(); + int i; + for (i=0;i<16;i++) + { + channelmap[i]=i; + channelPatchForced[i]=-1; + } + for (i=0;i<128;i++) patchmap[i]=i; + } + else + loadFile(name); +} + +MidiMapper::~MidiMapper() +{ + if (_filename) free(_filename); + deallocateMaps(); +} + +void MidiMapper::deallocateMaps(void) +{ + int i; + for (i=0;i<16;i++) channelKeymap[i]=NULL; + for (i=0;i<128;i++) patchKeymap[i]=NULL; + Keymap *km; + while (keymaps!=NULL) + { + km=keymaps->next; + delete keymaps; + keymaps=km; + } +} + +void MidiMapper::getValue(char *s,char *v) +{ + char *c=s; + while ((*c!=0)&&(*c!='=')) c++; + if (*c==0) v[0]=0; + else + { + c++; + while (*c!=0) + { + *v=*c; + c++;v++; + } + *v=0; + } +} + +void MidiMapper::removeSpaces(char *s) +{ + char *a=s; + while ((*a!=0)&&(*a==' ')) a++; + if (*a==0) {*s=0;return;}; + while (*a!=0) + { + while ((*a!=0)&&(*a!=' ')&&(*a!=10)&&(*a!=13)) + { + *s=*a; + s++; + a++; + } + while ((*a!=0)&&((*a==' ')||(*a==10)||(*a==13))) a++; + *s=' ';s++; + if (*a==0) {*s=0;return;}; + } + *s=0; + +} + +int MidiMapper::countWords(char *s) +{ + int c=0; + while (*s!=0) + { + if (*s==' ') c++; + s++; + } + return c; +} + +void MidiMapper::getWord(char *t,char *s,int w) +{ + int i=0; + *t=0; + while ((*s!=0)&&(i<w)) + { + if (*s==' ') i++; + s++; + } + while ((*s!=0)&&(*s!=' ')&&(*s!=10)&&(*s!=13)) + { + *t=*s; + t++;s++; + } + *t=0; +} + + +void MidiMapper::loadFile(const char *name) +{ + _ok=1; + FILE *fh = fopen(name,"rt"); + if ( fh == NULL ) { _ok = -1; return; }; + char s[101]; + s[0] = 0; + if ( _filename != NULL ) free(_filename); + _filename = strdup(name); +#ifdef MIDIMAPPERDEBUG + printf("Loading mapper ...\n"); +#endif + while (!feof(fh)) + { + s[0]=0; + while ((!feof(fh))&&((s[0]==0)||(s[0]=='#'))) fgets(s,100,fh); + if (strncmp(s,"DEFINE",6)==0) + { + if (strncmp(&s[7],"PATCHMAP",8)==0) readPatchmap(fh); + else + if (strncmp(&s[7],"KEYMAP",6)==0) readKeymap(fh,s); + else + if (strncmp(&s[7],"CHANNELMAP",10)==0) readChannelmap(fh); + else + { + printf("ERROR: Unknown DEFINE line in map file\n"); + _ok=0; + } + if (_ok==0) + { + printf("The midi map file will be ignored\n"); + fclose(fh); + return; + } + } + else if (strncmp(s,"OPTIONS",7)==0) readOptions(fh); + } + fclose(fh); +} + +MidiMapper::Keymap *MidiMapper::createKeymap(char *name,uchar use_same_note,uchar note) +{ + Keymap *km=new Keymap; + strncpy(km->name, name, KM_NAME_SIZE); + km->name[KM_NAME_SIZE - 1] = 0; + + int i; + if (use_same_note==1) + { + for (i=0;i<128;i++) + km->key[i]=note; + } + else + { + for (i=0;i<128;i++) + km->key[i]=i; + } + addKeymap(km); + return km; +} + +void MidiMapper::addKeymap(Keymap *newkm) +{ + Keymap *km=keymaps; + if (keymaps==NULL) + { + keymaps=newkm; + newkm->next=NULL; + return; + } + while (km->next!=NULL) km=km->next; + km->next=newkm; + newkm->next=NULL; + return; +} + +MidiMapper::Keymap *MidiMapper::keymap(char *n) +{ + Keymap *km=keymaps; + while ((km!=NULL)&&(strcmp(km->name,n)!=0)) km=km->next; + return km; +} + +void MidiMapper::readOptions(FILE *fh) +{ +#ifdef MIDIMAPPERDEBUG + printf("Loading Options ... \n"); +#endif + char s[101]; + char v[101]; + char t[101]; + int fin=0; + mapPitchBender=0; + while (!fin) + { + s[0]=0; + while ((s[0]==0)||(s[0]=='#')) fgets(s,100,fh); + if (strncmp(s,"PitchBenderRatio",16)==0) + { + getValue(s,v); + removeSpaces(v); + getWord(t,v,0); + mapPitchBender=1; + pitchBenderRatio=atoi(t); + } + else if (strncmp(s,"MapExpressionToVolumeEvents",27)==0) mapExpressionToVolumeEvents=1; + else if (strncmp(s,"END",3)==0) + { + fin=1; + } + else + { + printf("ERROR: Invalid option in OPTIONS section of map file : (%s)\n",s); + _ok=0; + return; + } + } +} + +void MidiMapper::readPatchmap(FILE *fh) +{ + char s[101]; + char v[101]; + char t[101]; + char name[256]; /* Longer than t and 'AllKeysTo' */ + int i=0; + int j,w; +#ifdef MIDIMAPPERDEBUG + printf("Loading Patch map ... \n"); +#endif + while (i<128) + { + s[0]=0; + while ((s[0]==0)||(s[0]=='#')) fgets(s,100,fh); + getValue(s,v); + removeSpaces(v); + w=countWords(v); + j=0; + patchKeymap[i]=NULL; + patchmap[i]=i; + while (j<w) + { + getWord(t,v,j); + if (strcmp(t,"AllKeysTo")==0) + { + j++; + if (j>=w) + { + printf("ERROR: Invalid option in PATCHMAP section of map file\n"); + _ok=0; + return; + } + getWord(t,v,j); + sprintf(name,"AllKeysTo%s",t); + patchKeymap[i]=createKeymap(name,1,atoi(t)); + } + else + { + patchmap[i]=atoi(t); + } + j++; + } + i++; + } + s[0]=0; + while ((s[0]==0)||(s[0]=='#')||(s[0]==10)||(s[0]==13)) fgets(s,100,fh); + if (strncmp(s,"END",3)!=0) + { + printf("ERROR: End of section not found in map file\n"); + _ok=0; + return; + } +} + +void MidiMapper::readKeymap(FILE *fh,char *first_line) +{ + char s[101]; + char v[101]; +#ifdef MIDIMAPPERDEBUG + printf("Loading Key map ... %s",first_line); +#endif + removeSpaces(first_line); + getWord(v,first_line,2); + Keymap *km=new Keymap; + strncpy(km->name, v, KM_NAME_SIZE); + km->name[KM_NAME_SIZE - 1] = 0; + + int i=0; + while (i<128) + { + s[0]=0; + while ((s[0]==0)||(s[0]=='#')) fgets(s,100,fh); + getValue(s,v); + removeSpaces(v); + km->key[i]=atoi(v); + i++; + } + s[0]=0; + while ((s[0]==0)||(s[0]=='#')||(s[0]==10)||(s[0]==13)) fgets(s,100,fh); + if (strncmp(s,"END",3)!=0) + { + printf("ERROR: End of section not found in map file\n"); + _ok=0; + return; + } + addKeymap(km); +} + +void MidiMapper::readChannelmap(FILE *fh) +{ + char s[101]; + char v[101]; + char t[101]; + int i=0; + int w,j; +#ifdef MIDIMAPPERDEBUG + printf("Loading Channel map ... \n"); +#endif + while (i<16) + { + s[0]=0; + while ((s[0]==0)||(s[0]=='#')) fgets(s,100,fh); + getValue(s,v); + removeSpaces(v); + w=countWords(v); + j=0; + channelKeymap[i]=NULL; + channelPatchForced[i]=-1; + channelmap[i]=i; + while (j<w) + { + getWord(t,v,j); + if (strcmp(t,"Keymap")==0) + { + j++; + if (j>=w) + { + printf("ERROR: Invalid option in CHANNELMAP section of map file\n"); + _ok=0; + return; + } + getWord(t,v,j); + channelKeymap[i]=keymap(t); + } + else if (strcmp(t,"ForcePatch")==0) + { + j++; + if (j>=w) + { + printf("ERROR: Invalid option in CHANNELMAP section of map file\n"); + _ok=0; + return; + } + getWord(t,v,j); + channelPatchForced[i]=atoi(t); + } + else + { + channelmap[i]=atoi(t); + } + j++; + } + i++; + } + s[0]=0; + while ((s[0]==0)||(s[0]=='#')||(s[0]==10)||(s[0]==13)) fgets(s,100,fh); + if (strncmp(s,"END",3)!=0) + { + printf("END of section not found in map file\n"); + _ok=0; + return; + } + +} + +const char *MidiMapper::filename(void) +{ + return (_filename)? _filename : ""; +} + +uchar MidiMapper::key(uchar chn,uchar pgm, uchar note) +{ + uchar notemapped=note; + if (patchKeymap[pgm]!=NULL) notemapped=patchKeymap[pgm]->key[note]; + if (channelKeymap[chn]!=NULL) notemapped=channelKeymap[chn]->key[note]; + return notemapped; +} + +uchar MidiMapper::patch(uchar chn,uchar pgm) +{ + return (channelPatchForced[chn] == -1) ? + patchmap[pgm] : (uchar)channelPatchForced[chn] ; +} + +void MidiMapper::pitchBender(uchar ,uchar &lsb,uchar &msb) +{ + if (mapPitchBender) + { + short pbs=((short)msb<<7) | (lsb & 0x7F); + pbs=pbs-0x2000; + short pbs2=(((long)pbs*pitchBenderRatio)/4096); +#ifdef MIDIMAPPERDEBUG + printf("Pitch Bender (%d): %d -> %d \n",chn,pbs,pbs2); +#endif + pbs2=pbs2+0x2000; + lsb=pbs2 & 0x7F; + msb=(pbs2 >> 7)&0x7F; + } +} + +void MidiMapper::controller(uchar ,uchar &ctl, uchar &) +{ + if ((mapExpressionToVolumeEvents)&&(ctl==11)) ctl=7; +} |