summaryrefslogtreecommitdiffstats
path: root/libkmid/midimapper.cc
diff options
context:
space:
mode:
Diffstat (limited to 'libkmid/midimapper.cc')
-rw-r--r--libkmid/midimapper.cc456
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;
+}