/************************************************************************** deviceman.cc - The device manager, that hides the use of midiOut 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. $Id$ Send comments and bug fixes to Antonio Larrosa ***************************************************************************/ #include "deviceman.h" #include "midiout.h" #include #include #include #include #include #include "sndcard.h" #include "synthout.h" #include "fmout.h" #include "gusout.h" #include "alsaout.h" #include "midimapper.h" #include "midispec.h" #ifdef HAVE_CONFIG_H #include #endif #ifdef HAVE_SYS_STAT_H #include #endif #ifdef HAVE_ALSA_ASOUNDLIB_H # define HAVE_ALSA_SUPPORT # include #elif defined(HAVE_SYS_ASOUNDLIB_H) # define HAVE_ALSA_SUPPORT # include #else #ifdef HAVE_LIBASOUND2 # define HAVE_ALSA_SUPPORT # include # include #elif defined(HAVE_LIBASOUND) # define HAVE_ALSA_SUPPORT # include #endif #endif #if 1 #include #include #include #endif //#define DEVICEMANDEBUG //#define GENERAL_DEBUG_MESSAGES SEQ_DEFINEBUF (4096); #define CONTROLTIMER #ifdef GENERAL_DEBUG_MESSAGES void DEBUGPRINTF(const char *format) { printf(format); } void DEBUGPRINTF(const char *format,int i) { printf(format,i); } void DEBUGPRINTF(const char *format,const char *s) { printf(format,s); } #else void DEBUGPRINTF(const char *) { } void DEBUGPRINTF(const char *,int ) { } void DEBUGPRINTF(const char *,const char * ) { } #endif DeviceManager::DeviceManager(int def) { #if 1 if (def==-1) { TDEInstance *tmp_instance=0L; if (!TDEGlobal::_instance) tmp_instance=new TDEInstance("nonKDEapp"); TDEConfig *config = new TDEConfig("kcmmidirc", true); config->setGroup("Configuration"); default_dev=config->readNumEntry("midiDevice",0); if ( default_dev < 0 ) default_dev=0; TQString mapurl(config->readPathEntry("mapFilename")); if ((config->readBoolEntry("useMidiMapper", false))&&(!mapurl.isEmpty())) { mapper_tmp = new MidiMapper( mapurl.mid(mapurl.find(":")+1 ).local8Bit() ); } else mapper_tmp = 0L; delete config; delete tmp_instance; } else #endif { default_dev = def; mapper_tmp = 0L; } initialized=0; _ok=1; alsa=false; device = 0L; m_rate=0; convertrate=10; seqfd=-1; timerstarted=0; n_midi=0; n_synths=0; n_total=0; midiinfo=0L; synthinfo=0L; for (int i=0;i<16;i++) chn2dev[i]=default_dev; } DeviceManager::~DeviceManager(void) { closeDev(); if (device) { for (int i=0;i=n_total) default_dev=0; DEBUGPRINTF("check : %d\n",r); return r; } return 0; } void DeviceManager::checkAlsa(void) { #ifdef HAVE_SYS_STAT_H struct stat buf; stat("/proc/asound", &buf); if ((stat("/proc/asound", &buf) == 0 ) && (S_ISDIR(buf.st_mode))) alsa=true; else alsa=false; #else #warning "ALSA won't be found at runtime" alsa=false; #endif } int DeviceManager::initManager(void) { checkAlsa(); if (!alsa) // We are using OSS { #ifdef HAVE_OSS_SUPPORT n_synths=0; n_midi=0; n_total=0; seqfd = open("/dev/sequencer", O_WRONLY | O_NONBLOCK, 0); if (seqfd==-1) { fprintf(stderr,"ERROR: Couldn't open /dev/sequencer to get some information\n"); _ok=0; return -1; } ioctl(seqfd,SNDCTL_SEQ_NRSYNTHS,&n_synths); ioctl(seqfd,SNDCTL_SEQ_NRMIDIS,&n_midi); n_total=n_midi+n_synths; if (n_midi==0) { fprintf(stderr,"ERROR: There's no midi port\n"); /* This could be a problem if the user don't have a synth neither, but not having any of both things is unusual */ // _ok=0; // return 1; } device=new MidiOut*[n_total]; midiinfo=new midi_info[n_midi]; synthinfo=new synth_info[n_synths]; int i; for (i=0;iopenDev(seqfd); // DEBUGPRINTF("%s ",device[i]->deviceName()); } // DEBUGPRINTF("\n"); for (int i=0;iok()) _ok=0; if (_ok==0) { for (int i=0;icloseDev(); // DEBUGPRINTF("DeviceMan :: ERROR : Closing devices\n"); return; } // DEBUGPRINTF("Devices opened\n"); } void DeviceManager::closeDev(void) { if (alsa) { if (device) for (int i=0;icloseDev(); return; } #ifdef HAVE_OSS_SUPPORT if (seqfd==-1) return; tmrStop(); if (device) for (int i=0;icloseDev(); /* DEBUGPRINTF("Closing devices : "); if (device!=NULL) for (int i=0;iinitDev(); DEBUGPRINTF("%s ",device[i]->deviceName()); // device[i]->closeDev(); }; DEBUGPRINTF("\n"); */ close(seqfd); seqfd=-1; #endif } void DeviceManager::initDev(void) { if (device!=0L) { // DEBUGPRINTF("Initializing devices :"); for (int i=0;iinitDev(); DEBUGPRINTF("%s ",device[i]->deviceName()); } DEBUGPRINTF("\n"); } } void DeviceManager::noteOn ( uchar chn, uchar note, uchar vel ) { MidiOut *midi=chntodev(chn); if (midi) midi->noteOn(chn,note,vel); } void DeviceManager::noteOff ( uchar chn, uchar note, uchar vel ) { MidiOut *midi=chntodev(chn); if (midi) midi->noteOff(chn,note,vel); } void DeviceManager::keyPressure ( uchar chn, uchar note, uchar vel ) { MidiOut *midi=chntodev(chn); if (midi) midi->keyPressure(chn,note,vel); } void DeviceManager::chnPatchChange ( uchar chn, uchar patch ) { MidiOut *midi=chntodev(chn); if (midi) midi->chnPatchChange(chn,patch); } void DeviceManager::chnPressure ( uchar chn, uchar vel ) { MidiOut *midi=chntodev(chn); if (midi) midi->chnPressure(chn,vel); } void DeviceManager::chnPitchBender ( uchar chn, uchar lsb, uchar msb ) { MidiOut *midi=chntodev(chn); if (midi) midi->chnPitchBender(chn,lsb,msb); } void DeviceManager::chnController ( uchar chn, uchar ctl , uchar v ) { MidiOut *midi=chntodev(chn); if (midi) midi->chnController(chn,ctl,v); } void DeviceManager::sysEx ( uchar *data,ulong size) { for (int i=0;isysex(data,size); } void DeviceManager::wait (double ticks) { #ifdef HAVE_ALSA_SUPPORT if (alsa) { ((AlsaOut *)device[default_dev])->wait(ticks); return; }; #endif #ifdef HAVE_OSS_SUPPORT unsigned long int t=(unsigned long int)(ticks/convertrate); if (lastwaittime==t) return; lastwaittime=t; SEQ_WAIT_TIME(t); SEQ_DUMPBUF(); #endif } //void DeviceManager::tmrSetTempo(int v) void DeviceManager::tmrSetTempo(int v) { #ifdef HAVE_ALSA_SUPPORT if (alsa) { ((AlsaOut *)device[default_dev])->tmrSetTempo(v); return; } #endif #ifdef HAVE_OSS_SUPPORT SEQ_SET_TEMPO(v); SEQ_DUMPBUF(); #endif } void DeviceManager::tmrStart(long int #ifdef HAVE_ALSA_SUPPORT tpcn /*name the argument only if it is used*/ #endif ) { #ifdef HAVE_ALSA_SUPPORT if (alsa) { ((AlsaOut *)device[default_dev])->tmrStart(tpcn); return; } #endif #ifdef HAVE_OSS_SUPPORT #ifdef CONTROLTIMER if (!timerstarted) { SEQ_START_TIMER(); SEQ_DUMPBUF(); timerstarted=1; } lastwaittime=0; #else SEQ_START_TIMER(); SEQ_DUMPBUF(); #endif #endif } void DeviceManager::tmrStop(void) { #ifdef HAVE_ALSA_SUPPORT if (alsa) { ((AlsaOut *)device[default_dev])->tmrStop(); return; } #endif #ifdef HAVE_OSS_SUPPORT #ifdef CONTROLTIMER if (timerstarted) { SEQ_STOP_TIMER(); SEQ_DUMPBUF(); timerstarted=0; } #else SEQ_STOP_TIMER(); SEQ_DUMPBUF(); #endif #endif } void DeviceManager::tmrContinue(void) { #ifdef HAVE_ALSA_SUPPORT if (alsa) { ((AlsaOut *)device[default_dev])->tmrContinue(); return; } #endif #ifdef HAVE_OSS_SUPPORT #ifdef CONTROLTIMER if (timerstarted) { SEQ_CONTINUE_TIMER(); SEQ_DUMPBUF(); } #else SEQ_CONTINUE_TIMER(); SEQ_DUMPBUF(); #endif #endif } void DeviceManager::sync(bool f) { #ifdef HAVE_ALSA_SUPPORT if (alsa) { ((AlsaOut *)device[default_dev])->sync(f); return ; }; #endif #ifdef HAVE_OSS_SUPPORT #ifdef DEVICEMANDEBUG printf("Sync %d\n",f); #endif if (f) { seqbuf_clean(); /* If you have any problem, try removing the next 2 lines, I though they would be useful here but the may have side effects */ ioctl(seqfd,SNDCTL_SEQ_RESET); ioctl(seqfd,SNDCTL_SEQ_PANIC); } else { seqbuf_dump(); ioctl(seqfd, SNDCTL_SEQ_SYNC); }; #endif } void DeviceManager::seqbuf_dump (void) { if (!alsa) { #ifdef HAVE_OSS_SUPPORT if (_seqbufptr) { int r=0; unsigned char *sb=_seqbuf; int w=_seqbufptr; r=write (seqfd, _seqbuf, _seqbufptr); #ifdef DEVICEMANDEBUG printf("%d == %d\n",r,w); printf("%d\n",(errno==EAGAIN)? 1 : 0); #endif while (((r == -1)&&(errno==EAGAIN))||(r != w)) { if ((r==-1)&&(errno==EAGAIN)) { usleep(1); } else if ((r>0)&&(r!=w)) { w-=r; sb+=r; } r=write (seqfd, sb, w); #ifdef DEVICEMANDEBUG printf("%d == %d\n",r,w); printf("%d\n",(errno==EAGAIN)? 1 : 0); #endif } } /* * if (_seqbufptr) * if (write (seqfd, _seqbuf, _seqbufptr) == -1) * { * printf("Error writing to /dev/sequencer in deviceManager::seqbuf_dump\n"); * perror ("write /dev/sequencer in seqbuf_dump\n"); * exit (-1); * } */ _seqbufptr = 0; #endif } } void DeviceManager::seqbuf_clean(void) { #ifdef HAVE_ALSA_SUPPORT if (alsa) ((AlsaOut *)device[default_dev])->seqbuf_clean(); else #endif #ifdef HAVE_OSS_SUPPORT _seqbufptr=0; #endif } const char *DeviceManager::name(int i) { #ifdef HAVE_OSS_SUPPORT if (checkInit()<0) {_ok = 0; return NULL;} if (alsa) { if (ideviceName(); } else { if (i=n_total) return; default_dev=i; for (int i=0;i<16;i++) chn2dev[i]=default_dev; } const char *DeviceManager::midiMapFilename(void) { if (device==0L) return ""; if (default_dev>=n_total) return ""; return (device[default_dev]!=NULL) ? device[default_dev]->midiMapFilename() : ""; } void DeviceManager::setMidiMap(MidiMapper *map) { if (map==NULL) return; mapper_tmp=map; if (default_dev>=n_total) {default_dev=0;return;}; if ((device==0L)||(device[default_dev]==NULL)) return; device[default_dev]->setMidiMapper(map); } int DeviceManager::setPatchesToUse(int *patchesused) { if (checkInit()<0) return -1; if ((device==0L)||(device[default_dev]==NULL)) return 0; if ((device[default_dev]->deviceType())==KMID_GUS) { GUSOut *gus=(GUSOut *)device[default_dev]; gus->setPatchesToUse(patchesused); } return 0; } void DeviceManager::setVolumePercentage(int v) { if (device!=0L) { for (int i=0;isetVolumePercentage(v); } } } void DeviceManager::setDeviceNumberForChannel(int chn, int dev) { chn2dev[chn]=dev; } void DeviceManager::allNotesOff(void) { for (int i=0;iallNotesOff(); }