You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
tdelibs/libtdemid/midimapper.cpp

457 lines
9.0 KiB

/**************************************************************************
midimapper.cpp - 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/libtdemid.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;
}