From 4f99f868f09bbffa2e15733b8b7c78eba07a199e Mon Sep 17 00:00:00 2001 From: Michele Calgaro Date: Sun, 6 Dec 2020 21:23:48 +0900 Subject: Renaming of files in preparation for code style tools. Signed-off-by: Michele Calgaro --- libtdemid/CMakeLists.txt | 8 +- libtdemid/Makefile.am | 8 +- libtdemid/alsaout.cc | 571 -------------------------- libtdemid/alsaout.cpp | 571 ++++++++++++++++++++++++++ libtdemid/alsaout.h | 2 +- libtdemid/dattypes.cc | 110 ----- libtdemid/dattypes.cpp | 110 +++++ libtdemid/deviceman.cc | 828 ------------------------------------- libtdemid/deviceman.cpp | 828 +++++++++++++++++++++++++++++++++++++ libtdemid/fmout.cc | 354 ---------------- libtdemid/fmout.cpp | 354 ++++++++++++++++ libtdemid/gusout.cc | 691 ------------------------------- libtdemid/gusout.cpp | 691 +++++++++++++++++++++++++++++++ libtdemid/libtdemid.cc | 263 ------------ libtdemid/libtdemid.cpp | 263 ++++++++++++ libtdemid/midfile.cc | 460 --------------------- libtdemid/midfile.cpp | 460 +++++++++++++++++++++ libtdemid/midimapper.cc | 456 -------------------- libtdemid/midimapper.cpp | 456 ++++++++++++++++++++ libtdemid/midiout.cc | 301 -------------- libtdemid/midiout.cpp | 301 ++++++++++++++ libtdemid/midistat.cc | 115 ------ libtdemid/midistat.cpp | 115 ++++++ libtdemid/mt32togm.cc | 18 - libtdemid/mt32togm.cpp | 18 + libtdemid/notearray.cc | 122 ------ libtdemid/notearray.cpp | 122 ++++++ libtdemid/player.cc | 959 ------------------------------------------- libtdemid/player.cpp | 959 +++++++++++++++++++++++++++++++++++++++++++ libtdemid/synthout.cc | 211 ---------- libtdemid/synthout.cpp | 211 ++++++++++ libtdemid/tests/Makefile.am | 4 +- libtdemid/tests/apitest.cc | 25 -- libtdemid/tests/apitest.cpp | 25 ++ libtdemid/tests/notesoff.cc | 24 -- libtdemid/tests/notesoff.cpp | 24 ++ libtdemid/track.cc | 566 ------------------------- libtdemid/track.cpp | 566 +++++++++++++++++++++++++ libtdemid/voiceman.cc | 279 ------------- libtdemid/voiceman.cpp | 279 +++++++++++++ 40 files changed, 6364 insertions(+), 6364 deletions(-) delete mode 100644 libtdemid/alsaout.cc create mode 100644 libtdemid/alsaout.cpp delete mode 100644 libtdemid/dattypes.cc create mode 100644 libtdemid/dattypes.cpp delete mode 100644 libtdemid/deviceman.cc create mode 100644 libtdemid/deviceman.cpp delete mode 100644 libtdemid/fmout.cc create mode 100644 libtdemid/fmout.cpp delete mode 100644 libtdemid/gusout.cc create mode 100644 libtdemid/gusout.cpp delete mode 100644 libtdemid/libtdemid.cc create mode 100644 libtdemid/libtdemid.cpp delete mode 100644 libtdemid/midfile.cc create mode 100644 libtdemid/midfile.cpp delete mode 100644 libtdemid/midimapper.cc create mode 100644 libtdemid/midimapper.cpp delete mode 100644 libtdemid/midiout.cc create mode 100644 libtdemid/midiout.cpp delete mode 100644 libtdemid/midistat.cc create mode 100644 libtdemid/midistat.cpp delete mode 100644 libtdemid/mt32togm.cc create mode 100644 libtdemid/mt32togm.cpp delete mode 100644 libtdemid/notearray.cc create mode 100644 libtdemid/notearray.cpp delete mode 100644 libtdemid/player.cc create mode 100644 libtdemid/player.cpp delete mode 100644 libtdemid/synthout.cc create mode 100644 libtdemid/synthout.cpp delete mode 100644 libtdemid/tests/apitest.cc create mode 100644 libtdemid/tests/apitest.cpp delete mode 100644 libtdemid/tests/notesoff.cc create mode 100644 libtdemid/tests/notesoff.cpp delete mode 100644 libtdemid/track.cc create mode 100644 libtdemid/track.cpp delete mode 100644 libtdemid/voiceman.cc create mode 100644 libtdemid/voiceman.cpp (limited to 'libtdemid') diff --git a/libtdemid/CMakeLists.txt b/libtdemid/CMakeLists.txt index 21338aac1..0cfce2c70 100644 --- a/libtdemid/CMakeLists.txt +++ b/libtdemid/CMakeLists.txt @@ -37,10 +37,10 @@ install( FILES set( target tdemid ) set( ${target}_SRCS - midiout.cc player.cc track.cc midimapper.cc - midfile.cc dattypes.cc midistat.cc deviceman.cc - synthout.cc fmout.cc gusout.cc alsaout.cc voiceman.cc - mt32togm.cc notearray.cc libtdemid.cc + midiout.cpp player.cpp track.cpp midimapper.cpp + midfile.cpp dattypes.cpp midistat.cpp deviceman.cpp + synthout.cpp fmout.cpp gusout.cpp alsaout.cpp voiceman.cpp + mt32togm.cpp notearray.cpp libtdemid.cpp ) tde_add_library( ${target} SHARED diff --git a/libtdemid/Makefile.am b/libtdemid/Makefile.am index 8cb347b01..2c1baf726 100644 --- a/libtdemid/Makefile.am +++ b/libtdemid/Makefile.am @@ -12,10 +12,10 @@ libtdemidinclude_HEADERS = midiout.h player.h track.h midimapper.h \ midispec.h libtdemid.h lib_LTLIBRARIES = libtdemid.la -libtdemid_la_SOURCES = midiout.cc player.cc track.cc midimapper.cc \ - midfile.cc dattypes.cc midistat.cc deviceman.cc synthout.cc \ - fmout.cc gusout.cc alsaout.cc voiceman.cc mt32togm.cc notearray.cc \ - libtdemid.cc +libtdemid_la_SOURCES = midiout.cpp player.cpp track.cpp midimapper.cpp \ + midfile.cpp dattypes.cpp midistat.cpp deviceman.cpp synthout.cpp \ + fmout.cpp gusout.cpp alsaout.cpp voiceman.cpp mt32togm.cpp notearray.cpp \ + libtdemid.cpp libtdemid_la_LDFLAGS = $(KDE_MT_LDFLAGS) -version-info 0:95 -no-undefined libtdemid_la_LIBADD = $(LIBASOUND) ../tdecore/libtdecore.la $(LIB_TQT) diff --git a/libtdemid/alsaout.cc b/libtdemid/alsaout.cc deleted file mode 100644 index 517852b25..000000000 --- a/libtdemid/alsaout.cc +++ /dev/null @@ -1,571 +0,0 @@ -/************************************************************************** - - alsaout.cc - class AlsaOut which represents an alsa client/port pair - This file is part of LibKMid 0.9.5 - Copyright (C) 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 - -***************************************************************************/ -#include "alsaout.h" -#include -#include -#include -#include "sndcard.h" -#include -#include -#include -#include -#include "midispec.h" - - -#ifdef HAVE_CONFIG_H -#include -#endif - -#ifdef HAVE_ALSA_ASOUNDLIB_H -# include -#elif defined(HAVE_SYS_ASOUNDLIB_H) -# include -#endif - -#ifdef HAVE_LIBASOUND2 -# define HAVE_ALSA_SEQ 1 -# define snd_seq_flush_output(x) snd_seq_drain_output(x) -#elif defined(HAVE_LIBASOUND) -# define HAVE_ALSA_SEQ 1 -# include -#endif - - -SEQ_USE_EXTBUF(); - -class AlsaOut::AlsaOutPrivate -{ -public: -#ifdef HAVE_ALSA_SEQ - AlsaOutPrivate(int _client, int _port, const char *cname,const char *pname) - { - handle=0L; - src=tgt=0L; - queue=0; - tPCN=1; - tgtclient=_client; - tgtport=_port; - tgtname=new char[strlen(cname)+strlen(pname)+3]; - strcpy(tgtname, cname); - strcat(tgtname, " "); - strcat(tgtname, pname); - ev=new snd_seq_event_t; - timerStarted=false; - } -#else - AlsaOutPrivate(int, int, const char *,const char *) - { - } -#endif - - ~AlsaOutPrivate() - { -#ifdef HAVE_ALSA_SEQ - delete ev; - delete tgtname; -#endif - } - -#ifdef HAVE_ALSA_SEQ - snd_seq_t *handle; - int client; - int queue; - snd_seq_addr_t *src; - snd_seq_addr_t *tgt; - - snd_seq_event_t *ev; - int tPCN; - - int tgtclient; - int tgtport; - char *tgtname; - - bool timerStarted; - -#endif -}; - -AlsaOut::AlsaOut(int d,int _client, int _port, const char *cname,const char *pname) : MidiOut (d) -{ - di = new AlsaOutPrivate( _client, _port, cname, pname); - seqfd = 0; - devicetype=KMID_ALSA; - device= d; - - volumepercentage=100; -#ifdef HAVE_ALSA_SEQ -// printf("%d %d %d (%s)\n",device, di->tgtclient, di->tgtport, di->tgtname); -#endif - - _ok=1; -} - -AlsaOut::~AlsaOut() -{ - closeDev(); - delete di; -} - -void AlsaOut::openDev (int) -{ -#ifndef HAVE_ALSA_SEQ - return; -#else - _ok=1; -#ifdef HAVE_LIBASOUND2 - if (snd_seq_open(&di->handle, "hw", SND_SEQ_OPEN_DUPLEX, 0) < 0) - fprintf(stderr, "Couldn't open sequencer: %s", snd_strerror(errno)); -#else - if (snd_seq_open(&di->handle, SND_SEQ_OPEN) < 0) - fprintf(stderr, "Couldn't open sequencer: %s", snd_strerror(errno)); -#endif - - di->queue = snd_seq_alloc_queue(di->handle); - if (di->queue < 0) {fprintf(stderr, "Couldn't allocate queue"); return; }; - di->client = snd_seq_client_id(di->handle); - if (di->client < 0) {fprintf(stderr, "Couldn't get client id"); return; }; - di->tgt = new snd_seq_addr_t; - di->tgt->client=di->tgtclient; - di->tgt->port=di->tgtport; - - di->src = new snd_seq_addr_t; - di->src->client = di->client; - int port = snd_seq_create_simple_port(di->handle, NULL, - SND_SEQ_PORT_CAP_WRITE | SND_SEQ_PORT_CAP_SUBS_WRITE - | SND_SEQ_PORT_CAP_READ, SND_SEQ_PORT_TYPE_MIDI_GENERIC); - if ( port < 0 ) - { - delete di->src; - delete di->tgt; - di->src=0; - di->tgt=0; - _ok=0; - time=0; - snd_seq_free_queue(di->handle, di->queue); - snd_seq_close(di->handle); - fprintf(stderr, "Cannot connect to %d:%d\n",di->tgtclient,di->tgtport); - return; - } - di->src->port = port; - - - int r=snd_seq_connect_to(di->handle, di->src->port, di->tgt->client, di->tgt->port); - if (r < 0) { _ok=0; fprintf(stderr, "Cannot connect to %d:%d\n",di->tgtclient,di->tgtport); } - time=0; -#endif -} - -void AlsaOut::closeDev (void) -{ - if (!ok()) return; -#ifdef HAVE_ALSA_SEQ - if (di->handle) - { - if (di->src) - { - snd_seq_delete_simple_port(di->handle,di->src->port); - delete di->src; - di->src=0; - } - if (di->tgt) - { - delete di->tgt; - di->tgt=0; - } - if (di->queue) - { - snd_seq_free_queue(di->handle, di->queue); - snd_seq_close(di->handle); - } - di->handle=0; - } - -#endif -} - -void AlsaOut::initDev (void) -{ -#ifdef HAVE_ALSA_SEQ - int chn; - if (!ok()) return; - uchar gm_reset[5]={0x7e, 0x7f, 0x09, 0x01, 0xf7}; - sysex(gm_reset, sizeof(gm_reset)); - for (chn=0;chn<16;chn++) - { - chnmute[chn]=0; - if (chn!=9) chnPatchChange(chn,0); - chnPressure(chn,64); - chnPitchBender(chn, 0x00, 0x40); - chnController(chn, CTL_MAIN_VOLUME,110*volumepercentage); - chnController(chn, CTL_EXT_EFF_DEPTH, 0); - chnController(chn, CTL_CHORUS_DEPTH, 0); - chnController(chn, 0x4a, 127); - } -#endif -} - -#ifdef HAVE_ALSA_SEQ -void AlsaOut::eventInit(snd_seq_event_t *ev) -{ - snd_seq_ev_clear(ev); - snd_seq_real_time_t tmp; - tmp.tv_sec=(time)/1000; - tmp.tv_nsec=(time%1000)*1000000; -// printf("time : %d %d %d\n",(int)time,(int)tmp.tv_sec, (int)tmp.tv_nsec); - if (!di->src) { fprintf(stderr,"AlsaOut::eventInit : no source\n"); return; } - ev->source = *di->src; - if (!di->tgt) { fprintf(stderr,"AlsaOut::eventInit : no target\n"); return; } - ev->dest = *di->tgt; - - snd_seq_ev_schedule_real(ev, di->queue, 0, &tmp); -} - -void AlsaOut::eventSend(snd_seq_event_t *ev) -{ - /*int err = */ snd_seq_event_output(di->handle, ev); -/* if (err < 0) - return; -*/ -//#ifndef SND_SEQ_IOCTL_GET_CLIENT_POOL - /* - * If this is not defined then block mode writes will not be - * working correctly. Therefore loop until all events are flushed - * out. - */ -/* err = 0; - do { - err = snd_seq_flush_output(di->handle); - if (err > 0) - usleep(2000); - } while (err > 0); - -#endif - - return ; -*/ -} - -void AlsaOut::timerEventSend(int type) -{ - snd_seq_event_t ev; - - ev.queue = di->queue; - ev.dest.client = SND_SEQ_CLIENT_SYSTEM; - ev.dest.port = SND_SEQ_PORT_SYSTEM_TIMER; - - ev.data.queue.queue = di->queue; - - ev.flags = SND_SEQ_TIME_STAMP_REAL | SND_SEQ_TIME_MODE_REL; - ev.time.time.tv_sec = 0; - ev.time.time.tv_nsec = 0; - - ev.type = type; - - snd_seq_event_output(di->handle, &ev); - snd_seq_flush_output(di->handle); -} - -#endif // HAVE_ALSA_SEQ - -#ifndef HAVE_ALSA_SEQ -void AlsaOut::noteOn (uchar , uchar , uchar ) -{ -#else -void AlsaOut::noteOn (uchar chn, uchar note, uchar vel) -{ - if (vel==0) - { - noteOff(chn,note,vel); - } - else - { - eventInit(di->ev); - snd_seq_ev_set_noteon(di->ev,map->channel(chn), map->key(chn,chnpatch[chn],note), vel); - eventSend(di->ev); - } -#endif -#ifdef MIDIOUTDEBUG - printfdebug("Note ON >\t chn : %d\tnote : %d\tvel: %d\n",chn,note,vel); -#endif -} - -#ifndef HAVE_ALSA_SEQ -void AlsaOut::noteOff (uchar , uchar , uchar ) -{ -#else -void AlsaOut::noteOff (uchar chn, uchar note, uchar vel) -{ - eventInit(di->ev); - snd_seq_ev_set_noteoff(di->ev,map->channel(chn), map->key(chn,chnpatch[chn],note), vel); - eventSend(di->ev); -#endif -#ifdef MIDIOUTDEBUG - printfdebug("Note OFF >\t chn : %d\tnote : %d\tvel: %d\n",chn,note,vel); -#endif -} - -#ifndef HAVE_ALSA_SEQ -void AlsaOut::keyPressure (uchar , uchar , uchar ) -{ -#else -void AlsaOut::keyPressure (uchar chn, uchar note, uchar vel) -{ - eventInit(di->ev); - snd_seq_ev_set_keypress(di->ev,map->channel(chn), map->key(chn,chnpatch[chn],note), vel); - eventSend(di->ev); -#endif -} - -#ifndef HAVE_ALSA_SEQ -void AlsaOut::chnPatchChange (uchar , uchar ) -{ -#else -void AlsaOut::chnPatchChange (uchar chn, uchar patch) -{ -#ifdef MIDIOUTDEBUG - printfdebug("PATCHCHANGE [%d->%d] %d -> %d\n", - chn,map->channel(chn),patch,map->patch(chn,patch)); -#endif - eventInit(di->ev); - snd_seq_ev_set_pgmchange(di->ev,map->channel(chn), map->patch(chn,patch)); - eventSend(di->ev); - chnpatch[chn]=patch; -#endif -} - -#ifndef HAVE_ALSA_SEQ -void AlsaOut::chnPressure (uchar , uchar ) -{ -#else -void AlsaOut::chnPressure (uchar chn, uchar vel) -{ - eventInit(di->ev); - snd_seq_ev_set_chanpress(di->ev,map->channel(chn), vel); - eventSend(di->ev); - - chnpressure[chn]=vel; -#endif -} - -#ifndef HAVE_ALSA_SEQ -void AlsaOut::chnPitchBender(uchar ,uchar , uchar ) -{ -#else -void AlsaOut::chnPitchBender(uchar chn,uchar lsb, uchar msb) -{ - map->pitchBender(chn,lsb,msb); - chnbender[chn]=((short)msb<<7) | (lsb & 0x7F); - chnbender[chn]=chnbender[chn]-0x2000; - - eventInit(di->ev); - snd_seq_ev_set_pitchbend(di->ev,map->channel(chn), chnbender[chn]); - eventSend(di->ev); -#endif -} - -#ifndef HAVE_ALSA_SEQ -void AlsaOut::chnController (uchar , uchar , uchar ) -{ -#else -void AlsaOut::chnController (uchar chn, uchar ctl, uchar v) -{ - map->controller(chn,ctl,v); - if ((ctl==11)||(ctl==7)) - { - v=(v*volumepercentage)/100; - if (v>127) v=127; - } - - eventInit(di->ev); - snd_seq_ev_set_controller(di->ev,map->channel(chn), ctl, v); - eventSend(di->ev); - - chncontroller[chn][ctl]=v; -#endif -} - -#ifndef HAVE_ALSA_SEQ -void AlsaOut::sysex(uchar *, ulong ) -{ -#else -void AlsaOut::sysex(uchar *data, ulong size) -{ - eventInit(di->ev); - snd_seq_ev_set_sysex(di->ev, size, data); - eventSend(di->ev); -#endif - -#ifdef MIDIOUTDEBUG - printfdebug("sysex\n"); -#endif -} - -#ifndef HAVE_ALSA_SEQ -void AlsaOut::channelSilence (uchar ) -{ -#else -void AlsaOut::channelSilence (uchar chn) -{ - uchar i; - for ( i=0; i<127; i++) - { - noteOff(chn,i,0); - } -#endif -} - -#ifndef HAVE_ALSA_SEQ -void AlsaOut::channelMute(uchar , int ) -{ -#else -void AlsaOut::channelMute(uchar chn, int a) -{ - if (a==1) - { - chnmute[chn]=a; - channelSilence(chn); - } - else if (a==0) - { - chnmute[chn]=a; - } - /* else ignore the call to this procedure */ -#endif -} - -void AlsaOut::seqbuf_dump (void) -{ - printf("You shouldn't be here.\n"); -} - -void AlsaOut::seqbuf_clean(void) -{ - printf("You shouldn't be here neither.\n"); -} - -void AlsaOut::wait(double ticks) -{ -// SEQ_WAIT_TIME(((int)(ticks/convertrate))); - time=static_cast(ticks); - -#ifdef MIDIOUTDEBUG - printfdebug("Wait >\t ticks: %g\n",ticks); -#endif -} - -#ifndef HAVE_ALSA_SEQ -void AlsaOut::tmrSetTempo(int ) -{ -#else -void AlsaOut::tmrSetTempo(int v) -{ - eventInit(di->ev); - di->ev->type = SND_SEQ_EVENT_TEMPO; - snd_seq_ev_set_direct(di->ev); - di->ev->data.queue.queue = di->queue; - di->ev->data.queue.param.value = v; - di->ev->dest.client = SND_SEQ_CLIENT_SYSTEM; - di->ev->dest.port = SND_SEQ_PORT_SYSTEM_TIMER; - snd_seq_event_output_direct(di->handle, di->ev); -#ifdef MIDIOUTDEBUG - printfdebug("SETTEMPO >\t tempo: %d\n",v); -#endif -#endif -} - -#ifndef HAVE_ALSA_SEQ -void AlsaOut::sync(int ) -{ -#else -void AlsaOut::sync(int i) -{ - if (i==1) - { - snd_seq_flush_output(di->handle); - } - - if (di->timerStarted && di->src) - { - eventInit(di->ev); - di->ev->dest = *di->src; - eventSend(di->ev); - snd_seq_flush_output(di->handle); - snd_seq_event_input(di->handle,&di->ev); - } - -#endif -} - -#ifndef HAVE_ALSA_SEQ -void AlsaOut::tmrStart(int ) -{ -#else -void AlsaOut::tmrStart(int tpcn) -{ - int ret; - di->timerStarted=true; - di->tPCN=tpcn; - -#ifdef HAVE_LIBASOUND2 - snd_seq_queue_tempo_t *queuetempo; - snd_seq_queue_tempo_alloca(&queuetempo); - snd_seq_queue_tempo_set_ppq(queuetempo, tpcn); - snd_seq_queue_tempo_set_tempo(queuetempo, 60*1000000/120); - ret = snd_seq_set_queue_tempo(di->handle, di->queue, queuetempo); -#else - snd_seq_queue_tempo_t queuetempo; - memset(&queuetempo, 0, sizeof(queuetempo)); - queuetempo.queue = di->queue; - queuetempo.ppq = tpcn; - queuetempo.tempo = 60*1000000/120; - ret = snd_seq_set_queue_tempo(di->handle, di->queue, &queuetempo); -#endif - - timerEventSend(SND_SEQ_EVENT_START); - snd_seq_start_queue(di->handle,di->queue,NULL); -#endif -} - -void AlsaOut::tmrStop(void) -{ -#ifdef HAVE_ALSA_SEQ - di->timerStarted=false; - timerEventSend(SND_SEQ_EVENT_STOP); -#endif -} - -void AlsaOut::tmrContinue(void) -{ -} - -const char * AlsaOut::deviceName(void) const -{ -#ifdef HAVE_ALSA_SEQ - return di->tgtname; -#else - return 0L; -#endif -} diff --git a/libtdemid/alsaout.cpp b/libtdemid/alsaout.cpp new file mode 100644 index 000000000..2e1b769f4 --- /dev/null +++ b/libtdemid/alsaout.cpp @@ -0,0 +1,571 @@ +/************************************************************************** + + alsaout.cpp - class AlsaOut which represents an alsa client/port pair + This file is part of LibKMid 0.9.5 + Copyright (C) 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 + +***************************************************************************/ +#include "alsaout.h" +#include +#include +#include +#include "sndcard.h" +#include +#include +#include +#include +#include "midispec.h" + + +#ifdef HAVE_CONFIG_H +#include +#endif + +#ifdef HAVE_ALSA_ASOUNDLIB_H +# include +#elif defined(HAVE_SYS_ASOUNDLIB_H) +# include +#endif + +#ifdef HAVE_LIBASOUND2 +# define HAVE_ALSA_SEQ 1 +# define snd_seq_flush_output(x) snd_seq_drain_output(x) +#elif defined(HAVE_LIBASOUND) +# define HAVE_ALSA_SEQ 1 +# include +#endif + + +SEQ_USE_EXTBUF(); + +class AlsaOut::AlsaOutPrivate +{ +public: +#ifdef HAVE_ALSA_SEQ + AlsaOutPrivate(int _client, int _port, const char *cname,const char *pname) + { + handle=0L; + src=tgt=0L; + queue=0; + tPCN=1; + tgtclient=_client; + tgtport=_port; + tgtname=new char[strlen(cname)+strlen(pname)+3]; + strcpy(tgtname, cname); + strcat(tgtname, " "); + strcat(tgtname, pname); + ev=new snd_seq_event_t; + timerStarted=false; + } +#else + AlsaOutPrivate(int, int, const char *,const char *) + { + } +#endif + + ~AlsaOutPrivate() + { +#ifdef HAVE_ALSA_SEQ + delete ev; + delete tgtname; +#endif + } + +#ifdef HAVE_ALSA_SEQ + snd_seq_t *handle; + int client; + int queue; + snd_seq_addr_t *src; + snd_seq_addr_t *tgt; + + snd_seq_event_t *ev; + int tPCN; + + int tgtclient; + int tgtport; + char *tgtname; + + bool timerStarted; + +#endif +}; + +AlsaOut::AlsaOut(int d,int _client, int _port, const char *cname,const char *pname) : MidiOut (d) +{ + di = new AlsaOutPrivate( _client, _port, cname, pname); + seqfd = 0; + devicetype=KMID_ALSA; + device= d; + + volumepercentage=100; +#ifdef HAVE_ALSA_SEQ +// printf("%d %d %d (%s)\n",device, di->tgtclient, di->tgtport, di->tgtname); +#endif + + _ok=1; +} + +AlsaOut::~AlsaOut() +{ + closeDev(); + delete di; +} + +void AlsaOut::openDev (int) +{ +#ifndef HAVE_ALSA_SEQ + return; +#else + _ok=1; +#ifdef HAVE_LIBASOUND2 + if (snd_seq_open(&di->handle, "hw", SND_SEQ_OPEN_DUPLEX, 0) < 0) + fprintf(stderr, "Couldn't open sequencer: %s", snd_strerror(errno)); +#else + if (snd_seq_open(&di->handle, SND_SEQ_OPEN) < 0) + fprintf(stderr, "Couldn't open sequencer: %s", snd_strerror(errno)); +#endif + + di->queue = snd_seq_alloc_queue(di->handle); + if (di->queue < 0) {fprintf(stderr, "Couldn't allocate queue"); return; }; + di->client = snd_seq_client_id(di->handle); + if (di->client < 0) {fprintf(stderr, "Couldn't get client id"); return; }; + di->tgt = new snd_seq_addr_t; + di->tgt->client=di->tgtclient; + di->tgt->port=di->tgtport; + + di->src = new snd_seq_addr_t; + di->src->client = di->client; + int port = snd_seq_create_simple_port(di->handle, NULL, + SND_SEQ_PORT_CAP_WRITE | SND_SEQ_PORT_CAP_SUBS_WRITE + | SND_SEQ_PORT_CAP_READ, SND_SEQ_PORT_TYPE_MIDI_GENERIC); + if ( port < 0 ) + { + delete di->src; + delete di->tgt; + di->src=0; + di->tgt=0; + _ok=0; + time=0; + snd_seq_free_queue(di->handle, di->queue); + snd_seq_close(di->handle); + fprintf(stderr, "Cannot connect to %d:%d\n",di->tgtclient,di->tgtport); + return; + } + di->src->port = port; + + + int r=snd_seq_connect_to(di->handle, di->src->port, di->tgt->client, di->tgt->port); + if (r < 0) { _ok=0; fprintf(stderr, "Cannot connect to %d:%d\n",di->tgtclient,di->tgtport); } + time=0; +#endif +} + +void AlsaOut::closeDev (void) +{ + if (!ok()) return; +#ifdef HAVE_ALSA_SEQ + if (di->handle) + { + if (di->src) + { + snd_seq_delete_simple_port(di->handle,di->src->port); + delete di->src; + di->src=0; + } + if (di->tgt) + { + delete di->tgt; + di->tgt=0; + } + if (di->queue) + { + snd_seq_free_queue(di->handle, di->queue); + snd_seq_close(di->handle); + } + di->handle=0; + } + +#endif +} + +void AlsaOut::initDev (void) +{ +#ifdef HAVE_ALSA_SEQ + int chn; + if (!ok()) return; + uchar gm_reset[5]={0x7e, 0x7f, 0x09, 0x01, 0xf7}; + sysex(gm_reset, sizeof(gm_reset)); + for (chn=0;chn<16;chn++) + { + chnmute[chn]=0; + if (chn!=9) chnPatchChange(chn,0); + chnPressure(chn,64); + chnPitchBender(chn, 0x00, 0x40); + chnController(chn, CTL_MAIN_VOLUME,110*volumepercentage); + chnController(chn, CTL_EXT_EFF_DEPTH, 0); + chnController(chn, CTL_CHORUS_DEPTH, 0); + chnController(chn, 0x4a, 127); + } +#endif +} + +#ifdef HAVE_ALSA_SEQ +void AlsaOut::eventInit(snd_seq_event_t *ev) +{ + snd_seq_ev_clear(ev); + snd_seq_real_time_t tmp; + tmp.tv_sec=(time)/1000; + tmp.tv_nsec=(time%1000)*1000000; +// printf("time : %d %d %d\n",(int)time,(int)tmp.tv_sec, (int)tmp.tv_nsec); + if (!di->src) { fprintf(stderr,"AlsaOut::eventInit : no source\n"); return; } + ev->source = *di->src; + if (!di->tgt) { fprintf(stderr,"AlsaOut::eventInit : no target\n"); return; } + ev->dest = *di->tgt; + + snd_seq_ev_schedule_real(ev, di->queue, 0, &tmp); +} + +void AlsaOut::eventSend(snd_seq_event_t *ev) +{ + /*int err = */ snd_seq_event_output(di->handle, ev); +/* if (err < 0) + return; +*/ +//#ifndef SND_SEQ_IOCTL_GET_CLIENT_POOL + /* + * If this is not defined then block mode writes will not be + * working correctly. Therefore loop until all events are flushed + * out. + */ +/* err = 0; + do { + err = snd_seq_flush_output(di->handle); + if (err > 0) + usleep(2000); + } while (err > 0); + +#endif + + return ; +*/ +} + +void AlsaOut::timerEventSend(int type) +{ + snd_seq_event_t ev; + + ev.queue = di->queue; + ev.dest.client = SND_SEQ_CLIENT_SYSTEM; + ev.dest.port = SND_SEQ_PORT_SYSTEM_TIMER; + + ev.data.queue.queue = di->queue; + + ev.flags = SND_SEQ_TIME_STAMP_REAL | SND_SEQ_TIME_MODE_REL; + ev.time.time.tv_sec = 0; + ev.time.time.tv_nsec = 0; + + ev.type = type; + + snd_seq_event_output(di->handle, &ev); + snd_seq_flush_output(di->handle); +} + +#endif // HAVE_ALSA_SEQ + +#ifndef HAVE_ALSA_SEQ +void AlsaOut::noteOn (uchar , uchar , uchar ) +{ +#else +void AlsaOut::noteOn (uchar chn, uchar note, uchar vel) +{ + if (vel==0) + { + noteOff(chn,note,vel); + } + else + { + eventInit(di->ev); + snd_seq_ev_set_noteon(di->ev,map->channel(chn), map->key(chn,chnpatch[chn],note), vel); + eventSend(di->ev); + } +#endif +#ifdef MIDIOUTDEBUG + printfdebug("Note ON >\t chn : %d\tnote : %d\tvel: %d\n",chn,note,vel); +#endif +} + +#ifndef HAVE_ALSA_SEQ +void AlsaOut::noteOff (uchar , uchar , uchar ) +{ +#else +void AlsaOut::noteOff (uchar chn, uchar note, uchar vel) +{ + eventInit(di->ev); + snd_seq_ev_set_noteoff(di->ev,map->channel(chn), map->key(chn,chnpatch[chn],note), vel); + eventSend(di->ev); +#endif +#ifdef MIDIOUTDEBUG + printfdebug("Note OFF >\t chn : %d\tnote : %d\tvel: %d\n",chn,note,vel); +#endif +} + +#ifndef HAVE_ALSA_SEQ +void AlsaOut::keyPressure (uchar , uchar , uchar ) +{ +#else +void AlsaOut::keyPressure (uchar chn, uchar note, uchar vel) +{ + eventInit(di->ev); + snd_seq_ev_set_keypress(di->ev,map->channel(chn), map->key(chn,chnpatch[chn],note), vel); + eventSend(di->ev); +#endif +} + +#ifndef HAVE_ALSA_SEQ +void AlsaOut::chnPatchChange (uchar , uchar ) +{ +#else +void AlsaOut::chnPatchChange (uchar chn, uchar patch) +{ +#ifdef MIDIOUTDEBUG + printfdebug("PATCHCHANGE [%d->%d] %d -> %d\n", + chn,map->channel(chn),patch,map->patch(chn,patch)); +#endif + eventInit(di->ev); + snd_seq_ev_set_pgmchange(di->ev,map->channel(chn), map->patch(chn,patch)); + eventSend(di->ev); + chnpatch[chn]=patch; +#endif +} + +#ifndef HAVE_ALSA_SEQ +void AlsaOut::chnPressure (uchar , uchar ) +{ +#else +void AlsaOut::chnPressure (uchar chn, uchar vel) +{ + eventInit(di->ev); + snd_seq_ev_set_chanpress(di->ev,map->channel(chn), vel); + eventSend(di->ev); + + chnpressure[chn]=vel; +#endif +} + +#ifndef HAVE_ALSA_SEQ +void AlsaOut::chnPitchBender(uchar ,uchar , uchar ) +{ +#else +void AlsaOut::chnPitchBender(uchar chn,uchar lsb, uchar msb) +{ + map->pitchBender(chn,lsb,msb); + chnbender[chn]=((short)msb<<7) | (lsb & 0x7F); + chnbender[chn]=chnbender[chn]-0x2000; + + eventInit(di->ev); + snd_seq_ev_set_pitchbend(di->ev,map->channel(chn), chnbender[chn]); + eventSend(di->ev); +#endif +} + +#ifndef HAVE_ALSA_SEQ +void AlsaOut::chnController (uchar , uchar , uchar ) +{ +#else +void AlsaOut::chnController (uchar chn, uchar ctl, uchar v) +{ + map->controller(chn,ctl,v); + if ((ctl==11)||(ctl==7)) + { + v=(v*volumepercentage)/100; + if (v>127) v=127; + } + + eventInit(di->ev); + snd_seq_ev_set_controller(di->ev,map->channel(chn), ctl, v); + eventSend(di->ev); + + chncontroller[chn][ctl]=v; +#endif +} + +#ifndef HAVE_ALSA_SEQ +void AlsaOut::sysex(uchar *, ulong ) +{ +#else +void AlsaOut::sysex(uchar *data, ulong size) +{ + eventInit(di->ev); + snd_seq_ev_set_sysex(di->ev, size, data); + eventSend(di->ev); +#endif + +#ifdef MIDIOUTDEBUG + printfdebug("sysex\n"); +#endif +} + +#ifndef HAVE_ALSA_SEQ +void AlsaOut::channelSilence (uchar ) +{ +#else +void AlsaOut::channelSilence (uchar chn) +{ + uchar i; + for ( i=0; i<127; i++) + { + noteOff(chn,i,0); + } +#endif +} + +#ifndef HAVE_ALSA_SEQ +void AlsaOut::channelMute(uchar , int ) +{ +#else +void AlsaOut::channelMute(uchar chn, int a) +{ + if (a==1) + { + chnmute[chn]=a; + channelSilence(chn); + } + else if (a==0) + { + chnmute[chn]=a; + } + /* else ignore the call to this procedure */ +#endif +} + +void AlsaOut::seqbuf_dump (void) +{ + printf("You shouldn't be here.\n"); +} + +void AlsaOut::seqbuf_clean(void) +{ + printf("You shouldn't be here neither.\n"); +} + +void AlsaOut::wait(double ticks) +{ +// SEQ_WAIT_TIME(((int)(ticks/convertrate))); + time=static_cast(ticks); + +#ifdef MIDIOUTDEBUG + printfdebug("Wait >\t ticks: %g\n",ticks); +#endif +} + +#ifndef HAVE_ALSA_SEQ +void AlsaOut::tmrSetTempo(int ) +{ +#else +void AlsaOut::tmrSetTempo(int v) +{ + eventInit(di->ev); + di->ev->type = SND_SEQ_EVENT_TEMPO; + snd_seq_ev_set_direct(di->ev); + di->ev->data.queue.queue = di->queue; + di->ev->data.queue.param.value = v; + di->ev->dest.client = SND_SEQ_CLIENT_SYSTEM; + di->ev->dest.port = SND_SEQ_PORT_SYSTEM_TIMER; + snd_seq_event_output_direct(di->handle, di->ev); +#ifdef MIDIOUTDEBUG + printfdebug("SETTEMPO >\t tempo: %d\n",v); +#endif +#endif +} + +#ifndef HAVE_ALSA_SEQ +void AlsaOut::sync(int ) +{ +#else +void AlsaOut::sync(int i) +{ + if (i==1) + { + snd_seq_flush_output(di->handle); + } + + if (di->timerStarted && di->src) + { + eventInit(di->ev); + di->ev->dest = *di->src; + eventSend(di->ev); + snd_seq_flush_output(di->handle); + snd_seq_event_input(di->handle,&di->ev); + } + +#endif +} + +#ifndef HAVE_ALSA_SEQ +void AlsaOut::tmrStart(int ) +{ +#else +void AlsaOut::tmrStart(int tpcn) +{ + int ret; + di->timerStarted=true; + di->tPCN=tpcn; + +#ifdef HAVE_LIBASOUND2 + snd_seq_queue_tempo_t *queuetempo; + snd_seq_queue_tempo_alloca(&queuetempo); + snd_seq_queue_tempo_set_ppq(queuetempo, tpcn); + snd_seq_queue_tempo_set_tempo(queuetempo, 60*1000000/120); + ret = snd_seq_set_queue_tempo(di->handle, di->queue, queuetempo); +#else + snd_seq_queue_tempo_t queuetempo; + memset(&queuetempo, 0, sizeof(queuetempo)); + queuetempo.queue = di->queue; + queuetempo.ppq = tpcn; + queuetempo.tempo = 60*1000000/120; + ret = snd_seq_set_queue_tempo(di->handle, di->queue, &queuetempo); +#endif + + timerEventSend(SND_SEQ_EVENT_START); + snd_seq_start_queue(di->handle,di->queue,NULL); +#endif +} + +void AlsaOut::tmrStop(void) +{ +#ifdef HAVE_ALSA_SEQ + di->timerStarted=false; + timerEventSend(SND_SEQ_EVENT_STOP); +#endif +} + +void AlsaOut::tmrContinue(void) +{ +} + +const char * AlsaOut::deviceName(void) const +{ +#ifdef HAVE_ALSA_SEQ + return di->tgtname; +#else + return 0L; +#endif +} diff --git a/libtdemid/alsaout.h b/libtdemid/alsaout.h index 016ca29c6..4dace44ce 100644 --- a/libtdemid/alsaout.h +++ b/libtdemid/alsaout.h @@ -1,4 +1,4 @@ -/* alsaout.cc - class AlsaOut which represents an alsa client/port pair +/* alsaout.cpp - class AlsaOut which represents an alsa client/port pair 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 diff --git a/libtdemid/dattypes.cc b/libtdemid/dattypes.cc deleted file mode 100644 index 218591fa4..000000000 --- a/libtdemid/dattypes.cc +++ /dev/null @@ -1,110 +0,0 @@ -/************************************************************************** - - dattypes.cc - Some always useful definitions and functions - 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 - -***************************************************************************/ -#include "dattypes.h" -#include - -ushort readShort(FILE *fh) -{ - uchar c1; - uchar c2; - - fread(&c1,1,1,fh); - fread(&c2,1,1,fh); - return (c1<<8)|c2; -} - -ulong readLong(FILE *fh) -{ - uchar c1; - uchar c2; - uchar c3; - uchar c4; - ulong l; - - fread(&c1,1,1,fh); - fread(&c2,1,1,fh); - fread(&c3,1,1,fh); - fread(&c4,1,1,fh); - l=((c1<<24)|(c2<<16)|(c3<<8)|c4); - return l; -} - -#ifdef DEBUG - -void printfdebug(const char *format, int a, int b, int c) -{ - char *s=(char *)format; - int i=0; - while (*s!=0) - { - if (*s=='%') i++; - s++; - } - switch (i) - { - case (1) : fprintf(stderr,format,a); break; - case (2) : fprintf(stderr,format,a,b); break; - case (3) : fprintf(stderr,format,a,b,c); break; - default : fprintf(stderr,format); break; - } - -} - -void printfdebug(const char *format, int a, long b) -{ - fprintf(stderr,format,a,b); -} - -void printfdebug(const char *format, double a, double b, double c) -{ - char *s=(char *)format; - int i=0; - while (*s!=0) - { - if (*s=='%') i++; - s++; - } - switch (i) - { - case (1) : fprintf(stderr,format,a); break; - case (2) : fprintf(stderr,format,a,b); break; - case (3) : fprintf(stderr,format,a,b,c); break; - default : fprintf(stderr,format); break; - } - -} -#else - -void printfdebug(const char *, int , int , int ) -{ -} -void printfdebug(const char *, int , long ) -{ -} -void printfdebug(const char *, double , double , double ) -{ -} -#endif diff --git a/libtdemid/dattypes.cpp b/libtdemid/dattypes.cpp new file mode 100644 index 000000000..7ae0aba52 --- /dev/null +++ b/libtdemid/dattypes.cpp @@ -0,0 +1,110 @@ +/************************************************************************** + + dattypes.cpp - Some always useful definitions and functions + 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 + +***************************************************************************/ +#include "dattypes.h" +#include + +ushort readShort(FILE *fh) +{ + uchar c1; + uchar c2; + + fread(&c1,1,1,fh); + fread(&c2,1,1,fh); + return (c1<<8)|c2; +} + +ulong readLong(FILE *fh) +{ + uchar c1; + uchar c2; + uchar c3; + uchar c4; + ulong l; + + fread(&c1,1,1,fh); + fread(&c2,1,1,fh); + fread(&c3,1,1,fh); + fread(&c4,1,1,fh); + l=((c1<<24)|(c2<<16)|(c3<<8)|c4); + return l; +} + +#ifdef DEBUG + +void printfdebug(const char *format, int a, int b, int c) +{ + char *s=(char *)format; + int i=0; + while (*s!=0) + { + if (*s=='%') i++; + s++; + } + switch (i) + { + case (1) : fprintf(stderr,format,a); break; + case (2) : fprintf(stderr,format,a,b); break; + case (3) : fprintf(stderr,format,a,b,c); break; + default : fprintf(stderr,format); break; + } + +} + +void printfdebug(const char *format, int a, long b) +{ + fprintf(stderr,format,a,b); +} + +void printfdebug(const char *format, double a, double b, double c) +{ + char *s=(char *)format; + int i=0; + while (*s!=0) + { + if (*s=='%') i++; + s++; + } + switch (i) + { + case (1) : fprintf(stderr,format,a); break; + case (2) : fprintf(stderr,format,a,b); break; + case (3) : fprintf(stderr,format,a,b,c); break; + default : fprintf(stderr,format); break; + } + +} +#else + +void printfdebug(const char *, int , int , int ) +{ +} +void printfdebug(const char *, int , long ) +{ +} +void printfdebug(const char *, double , double , double ) +{ +} +#endif diff --git a/libtdemid/deviceman.cc b/libtdemid/deviceman.cc deleted file mode 100644 index 82f973d3f..000000000 --- a/libtdemid/deviceman.cc +++ /dev/null @@ -1,828 +0,0 @@ -/************************************************************************** - - 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(); return ; } -#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(); -} diff --git a/libtdemid/deviceman.cpp b/libtdemid/deviceman.cpp new file mode 100644 index 000000000..18bb9fcc2 --- /dev/null +++ b/libtdemid/deviceman.cpp @@ -0,0 +1,828 @@ +/************************************************************************** + + deviceman.cpp - 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(); return ; } +#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(); +} diff --git a/libtdemid/fmout.cc b/libtdemid/fmout.cc deleted file mode 100644 index 72b3198c9..000000000 --- a/libtdemid/fmout.cc +++ /dev/null @@ -1,354 +0,0 @@ -/************************************************************************** - - fmout.cc - class fmOut which handles the /dev/sequencer device - for fm synths - This file is part of LibKMid 0.9.5 - Copyright (C) 1998,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 - -***************************************************************************/ -#include "fmout.h" -#include -#include -#include -#include "sndcard.h" -#include -#include -#include -#include -#include -#include -#include "midispec.h" -#ifdef HAVE_CONFIG_H -#include -#endif - -SEQ_USE_EXTBUF(); - -FMOut::FMOut( int d, int total ) -{ - seqfd = -1; - devicetype = KMID_FM; - device = d; - _ok = 1; - // Put opl=3 for opl/3 (better quality/ 6 voices) - // or opl=2 for fm output (less quality/ 18 voices, which is better imho) : - opl = 2; - // But be aware that opl=3 is not intended to be fully supported by now - - nvoices = total; - vm = new VoiceManager (nvoices); -} - -FMOut::~FMOut() -{ - closeDev(); - delete vm; - if (deleteFMPatchesDirectory) - { - free((char *)FMPatchesDirectory); - deleteFMPatchesDirectory = 0; - FMPatchesDirectory="/etc"; - } -} - -void FMOut::openDev (int sqfd) -{ -#ifdef HAVE_OSS_SUPPORT - _ok=1; - seqfd = sqfd; - //vm->clearLists(); - if ( seqfd == -1 ) - { - printfdebug("ERROR: Could not open /dev/sequencer\n"); - return; - } - - loadFMPatches(); -#endif - -} - -void FMOut::closeDev (void) -{ - if (!ok()) return; - vm->clearLists(); - //if (seqfd>=0) close(seqfd); - seqfd = -1; -} - -void FMOut::initDev (void) -{ -#ifdef HAVE_OSS_SUPPORT - int chn; - if (!ok()) return; - uchar gm_reset[5]={0x7e, 0x7f, 0x09, 0x01, 0xf7}; - sysex(gm_reset, sizeof(gm_reset)); - for (chn=0;chn<16;chn++) - { - chnmute[chn]=0; - chnPatchChange(chn,0); - chnPressure(chn,127); - chnPitchBender(chn, 0x00, 0x40); - chnController(chn, CTL_MAIN_VOLUME,127); - chnController(chn, CTL_EXT_EFF_DEPTH, 0); - chnController(chn, CTL_CHORUS_DEPTH, 0); - chnController(chn, 0x4a, 127); - } - - if (opl==3) ioctl(seqfd, SNDCTL_FM_4OP_ENABLE, &device); - SEQ_VOLUME_MODE(device,VOL_METHOD_LINEAR); - - for (int i = 0; i < nvoices; i++) - { - SEQ_CONTROL(device, i, SEQ_VOLMODE, VOL_METHOD_LINEAR); - SEQ_STOP_NOTE(device, i, vm->note(i), 64); - } -#endif -} - -void FMOut::loadFMPatches(void) -{ -#ifdef HAVE_OSS_SUPPORT - char patchesfile[strlen(FMPatchesDirectory)+7+1]; - char drumsfile[strlen(FMPatchesDirectory)+9+1]; - int size; - struct sbi_instrument instr; - char tmp[60]; - int i,j; - for ( i=0; i<256; i++ ) - patchloaded[i] = 0; - int stereoeffect=rand()%3; - FILE *fh; - int datasize; - - if (opl==3) - { - snprintf(patchesfile, sizeof(patchesfile), "%s/std.o3",FMPatchesDirectory); - size=60; - } - else - { - snprintf(patchesfile, sizeof(patchesfile), "%s/std.sb",FMPatchesDirectory); - size=52; - } - fh=fopen(patchesfile,"rb"); - if (fh==NULL) return; - - for (i=0;i<128;i++) - { - fread(tmp,size,1,fh); - patchloaded[i]=1; - instr.key = ((strncmp(tmp, "4OP", 3) == 0))? OPL3_PATCH : FM_PATCH; - datasize = (strncmp(tmp, "4OP", 3) == 0)? 22 : 11; - instr.device=device; - instr.channel = i; - // Let's get some stereo effect ... - tmp[46] = (tmp[46] & 0xcf) | ((++stereoeffect)<<4); - stereoeffect=stereoeffect%3; - for (j=0; j<22; j++) - instr.operators[j] = tmp[j+36]; - SEQ_WRPATCH(&instr,sizeof(instr)); - } - fclose(fh); - - if (opl==3) - { - snprintf(drumsfile, sizeof(drumsfile), "%s/drums.o3",FMPatchesDirectory); - } - else - { - snprintf(drumsfile, sizeof(drumsfile), "%s/drums.sb",FMPatchesDirectory); - } - - fh=fopen(drumsfile,"rb"); - if (fh==NULL) return; - - for (i=128;i<175;i++) - { - fread(tmp,size,1,fh); - patchloaded[i]=1; - instr.key = (strncmp(tmp, "4OP", 3) == 0)? OPL3_PATCH : FM_PATCH; - datasize = (strncmp(tmp, "4OP", 3) == 0)? 22 : 11; - instr.device=device; - instr.channel = i; - // Let's get some stereo effect ... - tmp[46] = (tmp[46] & 0xcf) | ((++stereoeffect)<<4); - stereoeffect=stereoeffect%3; - for (j=0; j<22; j++) - instr.operators[j] = tmp[j+36]; - SEQ_WRPATCH(&instr,sizeof(instr)); - } - fclose(fh); - -#ifdef FMOUTDEBUG - printfdebug("Patches loaded\n"); -#endif -#endif -} - -int FMOut::patch(int p) -{ - if (patchloaded[p]==1) return p; -#ifdef FMOUTDEBUG - printfdebug("Not loaded %d!\n",p); -#endif - p=0; - while ((p<256)&&(patchloaded[p]==0)) p++; - return p; -} - -void FMOut::noteOn (uchar chn, uchar note, uchar vel) -{ - if (vel==0) - { - noteOff(chn,note,vel); - } - else - { - if (chn==PERCUSSION_CHANNEL) - { - if (patchloaded[note+128]==0) return; - else - if (patchloaded[chnpatch[chn]]==0) return; - } - int v=vm->allocateVoice(chn,note); - int p; - if (chn==PERCUSSION_CHANNEL) - SEQ_SET_PATCH(device,v ,p=patch(note+128)) - else - SEQ_SET_PATCH(device,v ,p=map->patch(chn,chnpatch[chn])); - SEQ_BENDER(device, v, chnbender[chn]); - - SEQ_START_NOTE(device, v, note, vel); - // SEQ_CONTROL(device, v, CTL_MAIN_VOLUME, chncontroller[chn][CTL_MAIN_VOLUME]); - - SEQ_CHN_PRESSURE(device, v , chnpressure[chn]); - } - -#ifdef FMOUTDEBUG - printfdebug("Note ON >\t chn : %d\tnote : %d\tvel: %d\n",chn,note,vel); -#endif -} - -void FMOut::noteOff (uchar chn, uchar note, uchar vel) -{ - int i; - vm->initSearch(); - while ((i=vm->search(chn,note))!=-1) - { - SEQ_STOP_NOTE(device, i, note, vel); - vm->deallocateVoice(i); - } - -#ifdef FMOUTDEBUG - printfdebug("Note OFF >\t chn : %d\tnote : %d\tvel: %d\n",chn,note,vel); -#endif -} - -void FMOut::keyPressure (uchar chn, uchar note, uchar vel) -{ - int i; - vm->initSearch(); - while ((i=vm->search(chn,note))!=-1) - SEQ_KEY_PRESSURE(device, i, note,vel); -} - -void FMOut::chnPatchChange (uchar chn, uchar patch) -{ - if (chn==PERCUSSION_CHANNEL) return; - int i; - vm->initSearch(); - while ((i=vm->search(chn))!=-1) - SEQ_SET_PATCH(device,i,map->patch(chn,patch)); - - chnpatch[chn]=patch; -} - -void FMOut::chnPressure (uchar chn, uchar vel) -{ - int i; - vm->initSearch(); - while ((i=vm->search(chn))!=-1) - SEQ_CHN_PRESSURE(device, i , vel); - - chnpressure[chn]=vel; -} - -void FMOut::chnPitchBender(uchar chn,uchar lsb, uchar msb) -{ - chnbender[chn]=((int)msb<<7) | (lsb & 0x7F); - - int i; - vm->initSearch(); - while ((i=vm->search(chn))!=-1) - SEQ_BENDER(device, i, chnbender[chn]); - -} - -void FMOut::chnController (uchar chn, uchar ctl, uchar v) -{ - if ((ctl==11)||(ctl==7)) - { - v=(v*volumepercentage)/100; - if (v>127) v=127; - } - int i; - vm->initSearch(); - while ((i=vm->search(chn))!=-1) - SEQ_CONTROL(device, i, ctl, v); - - chncontroller[chn][ctl]=v; -} - -void FMOut::sysex(uchar *, ulong ) -{ - -} - -void FMOut::setFMPatchesDirectory(const char *dir) -{ - if ((dir==NULL)||(dir[0]==0)) return; - if (deleteFMPatchesDirectory) - free((char *)FMPatchesDirectory); - - FMPatchesDirectory = strdup(dir); - - deleteFMPatchesDirectory=1; -} - -void FMOut::setVolumePercentage ( int i ) -{ -#ifdef HAVE_OSS_SUPPORT - int fd=open("/dev/mixer0",O_RDWR,0); - if (fd==-1) return; - int a=i*255/100; - if (a>255) a=255; - a=(a<<8) | a; - if (ioctl(fd,MIXER_WRITE(SOUND_MIXER_SYNTH),&a) == -1) - printfdebug("ERROR writing to mixer\n"); - close(fd); -#endif - volumepercentage=i; -} - - -const char *FMOut::FMPatchesDirectory = "/etc"; -int FMOut::deleteFMPatchesDirectory = 0; diff --git a/libtdemid/fmout.cpp b/libtdemid/fmout.cpp new file mode 100644 index 000000000..eb069e51c --- /dev/null +++ b/libtdemid/fmout.cpp @@ -0,0 +1,354 @@ +/************************************************************************** + + fmout.cpp - class fmOut which handles the /dev/sequencer device + for fm synths + This file is part of LibKMid 0.9.5 + Copyright (C) 1998,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 + +***************************************************************************/ +#include "fmout.h" +#include +#include +#include +#include "sndcard.h" +#include +#include +#include +#include +#include +#include +#include "midispec.h" +#ifdef HAVE_CONFIG_H +#include +#endif + +SEQ_USE_EXTBUF(); + +FMOut::FMOut( int d, int total ) +{ + seqfd = -1; + devicetype = KMID_FM; + device = d; + _ok = 1; + // Put opl=3 for opl/3 (better quality/ 6 voices) + // or opl=2 for fm output (less quality/ 18 voices, which is better imho) : + opl = 2; + // But be aware that opl=3 is not intended to be fully supported by now + + nvoices = total; + vm = new VoiceManager (nvoices); +} + +FMOut::~FMOut() +{ + closeDev(); + delete vm; + if (deleteFMPatchesDirectory) + { + free((char *)FMPatchesDirectory); + deleteFMPatchesDirectory = 0; + FMPatchesDirectory="/etc"; + } +} + +void FMOut::openDev (int sqfd) +{ +#ifdef HAVE_OSS_SUPPORT + _ok=1; + seqfd = sqfd; + //vm->clearLists(); + if ( seqfd == -1 ) + { + printfdebug("ERROR: Could not open /dev/sequencer\n"); + return; + } + + loadFMPatches(); +#endif + +} + +void FMOut::closeDev (void) +{ + if (!ok()) return; + vm->clearLists(); + //if (seqfd>=0) close(seqfd); + seqfd = -1; +} + +void FMOut::initDev (void) +{ +#ifdef HAVE_OSS_SUPPORT + int chn; + if (!ok()) return; + uchar gm_reset[5]={0x7e, 0x7f, 0x09, 0x01, 0xf7}; + sysex(gm_reset, sizeof(gm_reset)); + for (chn=0;chn<16;chn++) + { + chnmute[chn]=0; + chnPatchChange(chn,0); + chnPressure(chn,127); + chnPitchBender(chn, 0x00, 0x40); + chnController(chn, CTL_MAIN_VOLUME,127); + chnController(chn, CTL_EXT_EFF_DEPTH, 0); + chnController(chn, CTL_CHORUS_DEPTH, 0); + chnController(chn, 0x4a, 127); + } + + if (opl==3) ioctl(seqfd, SNDCTL_FM_4OP_ENABLE, &device); + SEQ_VOLUME_MODE(device,VOL_METHOD_LINEAR); + + for (int i = 0; i < nvoices; i++) + { + SEQ_CONTROL(device, i, SEQ_VOLMODE, VOL_METHOD_LINEAR); + SEQ_STOP_NOTE(device, i, vm->note(i), 64); + } +#endif +} + +void FMOut::loadFMPatches(void) +{ +#ifdef HAVE_OSS_SUPPORT + char patchesfile[strlen(FMPatchesDirectory)+7+1]; + char drumsfile[strlen(FMPatchesDirectory)+9+1]; + int size; + struct sbi_instrument instr; + char tmp[60]; + int i,j; + for ( i=0; i<256; i++ ) + patchloaded[i] = 0; + int stereoeffect=rand()%3; + FILE *fh; + int datasize; + + if (opl==3) + { + snprintf(patchesfile, sizeof(patchesfile), "%s/std.o3",FMPatchesDirectory); + size=60; + } + else + { + snprintf(patchesfile, sizeof(patchesfile), "%s/std.sb",FMPatchesDirectory); + size=52; + } + fh=fopen(patchesfile,"rb"); + if (fh==NULL) return; + + for (i=0;i<128;i++) + { + fread(tmp,size,1,fh); + patchloaded[i]=1; + instr.key = ((strncmp(tmp, "4OP", 3) == 0))? OPL3_PATCH : FM_PATCH; + datasize = (strncmp(tmp, "4OP", 3) == 0)? 22 : 11; + instr.device=device; + instr.channel = i; + // Let's get some stereo effect ... + tmp[46] = (tmp[46] & 0xcf) | ((++stereoeffect)<<4); + stereoeffect=stereoeffect%3; + for (j=0; j<22; j++) + instr.operators[j] = tmp[j+36]; + SEQ_WRPATCH(&instr,sizeof(instr)); + } + fclose(fh); + + if (opl==3) + { + snprintf(drumsfile, sizeof(drumsfile), "%s/drums.o3",FMPatchesDirectory); + } + else + { + snprintf(drumsfile, sizeof(drumsfile), "%s/drums.sb",FMPatchesDirectory); + } + + fh=fopen(drumsfile,"rb"); + if (fh==NULL) return; + + for (i=128;i<175;i++) + { + fread(tmp,size,1,fh); + patchloaded[i]=1; + instr.key = (strncmp(tmp, "4OP", 3) == 0)? OPL3_PATCH : FM_PATCH; + datasize = (strncmp(tmp, "4OP", 3) == 0)? 22 : 11; + instr.device=device; + instr.channel = i; + // Let's get some stereo effect ... + tmp[46] = (tmp[46] & 0xcf) | ((++stereoeffect)<<4); + stereoeffect=stereoeffect%3; + for (j=0; j<22; j++) + instr.operators[j] = tmp[j+36]; + SEQ_WRPATCH(&instr,sizeof(instr)); + } + fclose(fh); + +#ifdef FMOUTDEBUG + printfdebug("Patches loaded\n"); +#endif +#endif +} + +int FMOut::patch(int p) +{ + if (patchloaded[p]==1) return p; +#ifdef FMOUTDEBUG + printfdebug("Not loaded %d!\n",p); +#endif + p=0; + while ((p<256)&&(patchloaded[p]==0)) p++; + return p; +} + +void FMOut::noteOn (uchar chn, uchar note, uchar vel) +{ + if (vel==0) + { + noteOff(chn,note,vel); + } + else + { + if (chn==PERCUSSION_CHANNEL) + { + if (patchloaded[note+128]==0) return; + else + if (patchloaded[chnpatch[chn]]==0) return; + } + int v=vm->allocateVoice(chn,note); + int p; + if (chn==PERCUSSION_CHANNEL) + SEQ_SET_PATCH(device,v ,p=patch(note+128)) + else + SEQ_SET_PATCH(device,v ,p=map->patch(chn,chnpatch[chn])); + SEQ_BENDER(device, v, chnbender[chn]); + + SEQ_START_NOTE(device, v, note, vel); + // SEQ_CONTROL(device, v, CTL_MAIN_VOLUME, chncontroller[chn][CTL_MAIN_VOLUME]); + + SEQ_CHN_PRESSURE(device, v , chnpressure[chn]); + } + +#ifdef FMOUTDEBUG + printfdebug("Note ON >\t chn : %d\tnote : %d\tvel: %d\n",chn,note,vel); +#endif +} + +void FMOut::noteOff (uchar chn, uchar note, uchar vel) +{ + int i; + vm->initSearch(); + while ((i=vm->search(chn,note))!=-1) + { + SEQ_STOP_NOTE(device, i, note, vel); + vm->deallocateVoice(i); + } + +#ifdef FMOUTDEBUG + printfdebug("Note OFF >\t chn : %d\tnote : %d\tvel: %d\n",chn,note,vel); +#endif +} + +void FMOut::keyPressure (uchar chn, uchar note, uchar vel) +{ + int i; + vm->initSearch(); + while ((i=vm->search(chn,note))!=-1) + SEQ_KEY_PRESSURE(device, i, note,vel); +} + +void FMOut::chnPatchChange (uchar chn, uchar patch) +{ + if (chn==PERCUSSION_CHANNEL) return; + int i; + vm->initSearch(); + while ((i=vm->search(chn))!=-1) + SEQ_SET_PATCH(device,i,map->patch(chn,patch)); + + chnpatch[chn]=patch; +} + +void FMOut::chnPressure (uchar chn, uchar vel) +{ + int i; + vm->initSearch(); + while ((i=vm->search(chn))!=-1) + SEQ_CHN_PRESSURE(device, i , vel); + + chnpressure[chn]=vel; +} + +void FMOut::chnPitchBender(uchar chn,uchar lsb, uchar msb) +{ + chnbender[chn]=((int)msb<<7) | (lsb & 0x7F); + + int i; + vm->initSearch(); + while ((i=vm->search(chn))!=-1) + SEQ_BENDER(device, i, chnbender[chn]); + +} + +void FMOut::chnController (uchar chn, uchar ctl, uchar v) +{ + if ((ctl==11)||(ctl==7)) + { + v=(v*volumepercentage)/100; + if (v>127) v=127; + } + int i; + vm->initSearch(); + while ((i=vm->search(chn))!=-1) + SEQ_CONTROL(device, i, ctl, v); + + chncontroller[chn][ctl]=v; +} + +void FMOut::sysex(uchar *, ulong ) +{ + +} + +void FMOut::setFMPatchesDirectory(const char *dir) +{ + if ((dir==NULL)||(dir[0]==0)) return; + if (deleteFMPatchesDirectory) + free((char *)FMPatchesDirectory); + + FMPatchesDirectory = strdup(dir); + + deleteFMPatchesDirectory=1; +} + +void FMOut::setVolumePercentage ( int i ) +{ +#ifdef HAVE_OSS_SUPPORT + int fd=open("/dev/mixer0",O_RDWR,0); + if (fd==-1) return; + int a=i*255/100; + if (a>255) a=255; + a=(a<<8) | a; + if (ioctl(fd,MIXER_WRITE(SOUND_MIXER_SYNTH),&a) == -1) + printfdebug("ERROR writing to mixer\n"); + close(fd); +#endif + volumepercentage=i; +} + + +const char *FMOut::FMPatchesDirectory = "/etc"; +int FMOut::deleteFMPatchesDirectory = 0; diff --git a/libtdemid/gusout.cc b/libtdemid/gusout.cc deleted file mode 100644 index 69aae3927..000000000 --- a/libtdemid/gusout.cc +++ /dev/null @@ -1,691 +0,0 @@ -/************************************************************************** - - gusout.cc - class GUSOut which implements support for Gravis - Ultrasound cards through a /dev/sequencer device - This file is part of LibKMid 0.9.5 - Copyright (C) 1998,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 - -***************************************************************************/ -#include "gusout.h" -#include "sndcard.h" -#include "midispec.h" -#include "gusvoices.h" -#include -#include -#include -#include -#include -#include -#include -#include -#include -#ifdef HAVE_CONFIG_H -#include -#endif - -SEQ_USE_EXTBUF(); - -#ifdef HAVE_OSS_SUPPORT -struct pat_header -{ - char magic[12]; - char version[10]; - char description[60]; - unsigned char instruments; - char voices; - char channels; - unsigned short nr_waveforms; - unsigned short master_volume; - unsigned long data_size; -}; -struct sample_header -{ - char name[7]; - unsigned char fractions; - long len; - long loop_start; - long loop_end; - unsigned short base_freq; - long low_note; - long high_note; - long base_note; - short detune; - unsigned char panning; - - unsigned char envelope_rate[6]; - unsigned char envelope_offset[6]; - - unsigned char tremolo_sweep; - unsigned char tremolo_rate; - unsigned char tremolo_depth; - - unsigned char vibrato_sweep; - unsigned char vibrato_rate; - unsigned char vibrato_depth; - - char modes; - - short scale_frequency; - unsigned short scale_factor; -}; - -int get_dint(unsigned char *p) -{ - unsigned int v=0; - - for (int i=0;i<4;i++) - { - v |= (p[i] << (i*8)); - } - return (int)v; -} - -unsigned short get_word(unsigned char *p) -{ - unsigned short v=0; - - for (int i=0;i<2;i++) - v |= (*p++ << (i*8)); - return (short)v; -} - -#endif - -GUSOut::GUSOut(int d,int total) -{ - seqfd = -1; - devicetype=KMID_GUS; - device= d; - _ok=1; - - use8bit=0; - nvoices=total; - vm=new VoiceManager(nvoices); -} - -GUSOut::~GUSOut() -{ - closeDev(); - - delete vm; - if (delete_GUS_patches_directory) - { - free((char *)GUS_patches_directory); - delete_GUS_patches_directory = 0; - GUS_patches_directory="/etc"; - } -} - -void GUSOut::openDev (int sqfd) -{ - _ok=1; - seqfd = sqfd; - //vm->clearLists(); - if (seqfd==-1) - { - printfdebug("ERROR: Could not open /dev/sequencer\n"); - return; - } - -#ifdef HAVE_OSS_SUPPORT - - //seqbuf_clean(); - //ioctl(seqfd,SNDCTL_SEQ_RESET); - //ioctl(seqfd,SNDCTL_SEQ_PANIC); - - if (ioctl(seqfd, SNDCTL_SEQ_RESETSAMPLES, &device)==-1) - { - printfdebug("Error reseting gus samples. Please report\n"); - }; - use8bit=0; - totalmemory = device; - ioctl(seqfd, SNDCTL_SYNTH_MEMAVL, &totalmemory); - freememory = device; - ioctl(seqfd, SNDCTL_SYNTH_MEMAVL, &freememory); - -#endif - - -} - -void GUSOut::closeDev (void) -{ - if (!ok()) return; - vm->clearLists(); - //if (seqfd>=0) - // close(seqfd); - seqfd=-1; -} - -void GUSOut::initDev (void) -{ -#ifdef HAVE_OSS_SUPPORT - int chn; - if (!ok()) return; - uchar gm_reset[5]={0x7e, 0x7f, 0x09, 0x01, 0xf7}; - sysex(gm_reset, sizeof(gm_reset)); - for (chn=0;chn<16;chn++) - { - chnmute[chn]=0; - chnPatchChange(chn,0); - // chnPressure(chn,127); - chnPitchBender(chn, 0x00, 0x40); - chnController(chn, CTL_MAIN_VOLUME,127); - chnController(chn, CTL_EXT_EFF_DEPTH, 0); - chnController(chn, CTL_CHORUS_DEPTH, 0); - chnController(chn, 0x4a, 127); - } - - - for (int i = 0; i < nvoices; i++) - { - SEQ_CONTROL(device, i, SEQ_VOLMODE, VOL_METHOD_LINEAR); - SEQ_STOP_NOTE(device, i, vm->note(i), 64); - } - -#endif -} - - -int GUSOut::patch(int p) -{ - if (patchloaded[p]==1) return p; - printfdebug("Not loaded %d!\n",p); - p=0; - while ((p<256)&&(patchloaded[p]==0)) p++; - return p; -} - -void GUSOut::noteOn (uchar chn, uchar note, uchar vel) -{ - if (vel==0) - { - noteOff(chn,note,vel); - } - else - { - if (chn==PERCUSSION_CHANNEL) - { - if (patchloaded[note+128]==0) return; - else - if (patchloaded[chnpatch[chn]]==0) return; - }; - int v=vm->allocateVoice(chn,note); - int p; - if (chn==PERCUSSION_CHANNEL) - SEQ_SET_PATCH(device,v ,p=patch(note+128)) - else - SEQ_SET_PATCH(device,v ,p=map->patch(chn,chnpatch[chn])); - SEQ_BENDER(device, v, chnbender[chn]); - - SEQ_START_NOTE(device, v, note, vel); - // SEQ_CONTROL(device, v, CTL_MAIN_VOLUME, chncontroller[chn][CTL_MAIN_VOLUME]); - SEQ_CHN_PRESSURE(device, v , chnpressure[chn]); - } - - printfdebug("Note ON >\t chn : %d\tnote : %d\tvel: %d\n",chn,note,vel); -} - -void GUSOut::noteOff (uchar chn, uchar note, uchar vel) -{ - int i; - vm->initSearch(); - while ((i=vm->search(chn,note))!=-1) - { - SEQ_STOP_NOTE(device, i, note, vel); - vm->deallocateVoice(i); - } - -#ifdef GUSOUTDEBUG - printf("Note OFF >\t chn : %d\tnote : %d\tvel: %d\n",chn,note,vel); -#endif -} - -void GUSOut::keyPressure (uchar chn, uchar note, uchar vel) -{ - int i; - vm->initSearch(); - while ((i=vm->search(chn,note))!=-1) - SEQ_KEY_PRESSURE(device, i, note,vel); -} - -void GUSOut::chnPatchChange (uchar chn, uchar patch) -{ - if (chn==PERCUSSION_CHANNEL) return; - int i; - vm->initSearch(); - while ((i=vm->search(chn))!=-1) - SEQ_SET_PATCH(device,i,map->patch(chn,patch)); - chnpatch[chn]=patch; - -} - -void GUSOut::chnPressure (uchar /*chn*/, uchar /*vel*/) -{ - /* int i; - vm->initSearch(); - while ((i=vm->search(chn))!=-1) - SEQ_CHN_PRESSURE(device, i , vel); - chnpressure[chn]=vel; - */ -} - -void GUSOut::chnPitchBender(uchar chn,uchar lsb, uchar msb) -{ - chnbender[chn]=((int)msb<<7) | (lsb & 0x7F); - - int i; - vm->initSearch(); - while ((i=vm->search(chn))!=-1) - SEQ_BENDER(device, i, chnbender[chn]); -} - -void GUSOut::chnController (uchar chn, uchar ctl, uchar v) -{ - if ((ctl==11)||(ctl==7)) - { - v=(v*volumepercentage)/100; - if (v>127) v=127; - }; - - int i; - vm->initSearch(); - while ((i=vm->search(chn))!=-1) - SEQ_CONTROL(device, i, ctl, v); - - chncontroller[chn][ctl]=v; -} - -void GUSOut::sysex(uchar *, ulong ) -{ - -} - -void GUSOut::setGUSPatchesDirectory(const char *dir) -{ - if ((dir==NULL)||(dir[0]==0)) return; - if (delete_GUS_patches_directory) - free((char *)GUS_patches_directory); - - GUS_patches_directory = strdup(dir); - delete_GUS_patches_directory=1; -} - -const char *GUSOut::patchName(int pgm) -{ - return GUS_voice_names[pgm]; -} - - -int GUSOut::loadPatch(int pgm) -{ -#ifdef HAVE_OSS_SUPPORT - struct pat_header header; - struct sample_header sample; - if (patchloaded[pgm]==1) - { -#ifdef GUSOUTDEBUG - printf("Trying to reload a patch. This should never happen, please report.\n"); -#endif - return 0; - } - if ((patchName(pgm)==NULL)||((patchName(pgm))[0]==0)) - { -#ifdef GUSOUTDEBUG - printf("Couldn't guess patch name for patch number %d\n",pgm); -#endif - return -1; - } - char *s=new char[strlen(GUS_patches_directory)+strlen(patchName(pgm))+10]; - if (s==NULL) return -1; - sprintf(s,"%s/%s.pat",GUS_patches_directory,patchName(pgm)); -#ifdef GUSOUTDEBUG - printf("Loading patch : %s\n",s); -#endif - struct patch_info *patch=NULL; - struct stat info; - if (stat(s, &info)==-1) - { -#ifdef GUSOUTDEBUG - printf("File %s doesn't exist\n",s); -#endif - return -1; - } - - FILE *fh=fopen(s,"rb"); - if (fh==NULL) - { -#ifdef GUSOUTDEBUG - printf("Couldn't open patch %s\n",s); -#endif - return -1; - } - - unsigned char tmp[256]; - if (fread(tmp,1,0xef,fh)!=0xef) - { - fclose(fh); -#ifdef GUSOUTDEBUG - printf("Short file ! \n"); -#endif - return -1; - } - memcpy ((char *) &header, tmp, sizeof (header)); - - if (strncmp(header.magic,"GF1PATCH110",12)!=0) - { -#ifdef GUSOUTDEBUG - printf("File %s is corrupted or it isn't a patch file\n",s); -#endif - return -1; - } - if (strncmp(header.version,"ID#000002",10)!=0) - { -#ifdef GUSOUTDEBUG - printf("File %s's version is not supported\n",s); -#endif - return -1; - } - unsigned short nWaves= *(unsigned short *)&tmp[85]; -#ifdef GUSOUTDEBUG - unsigned short masterVolume= *(unsigned short *)&tmp[87]; - printf("nWaves: %d\n",nWaves); - printf("masterVolume : %d\n",masterVolume); -#endif - - unsigned short i; - int offset=0xef; - for (i=0;ikey = GUS_PATCH; - patch->device_no = device; - patch->instr_no = pgm; - patch->mode = sample.modes | WAVE_TREMOLO | WAVE_VIBRATO | WAVE_SCALE; - patch->len = sample.len; - patch->loop_start = sample.loop_start; - patch->loop_end = sample.loop_end; - patch->base_note = sample.base_note; - patch->high_note = sample.high_note; - patch->low_note = sample.low_note; - patch->base_freq = sample.base_freq; - patch->detuning = sample.detune; - patch->panning = (sample.panning - 7) * 16; - - memcpy (patch->env_rate, sample.envelope_rate, 6); - memcpy (patch->env_offset, sample.envelope_offset, 6); - - patch->tremolo_sweep = sample.tremolo_sweep; - patch->tremolo_rate = sample.tremolo_rate; - patch->tremolo_depth = sample.tremolo_depth; - - patch->vibrato_sweep = sample.vibrato_sweep; - patch->vibrato_rate = sample.vibrato_rate; - patch->vibrato_depth = sample.vibrato_depth; - - patch->scale_frequency = sample.scale_frequency; - patch->scale_factor = sample.scale_factor; - - patch->volume = header.master_volume; - - if (fseek (fh, offset, 0) == -1) - { - fclose(fh); - return -1; - } - - if ((long)fread (patch->data, 1,sample.len,fh) != sample.len) - { -#ifdef GUSOUTDEBUG - printf ("Short file\n"); -#endif - return -1; - } - - SEQ_WRPATCH (patch, sizeof (*patch) + sample.len); - - offset = offset + sample.len; - - } - patchloaded[pgm]=1; - - fclose(fh); - free(patch); // Shouldn't this 'free' be within the 'for' loop ? - delete s; - freememory = device; - ioctl(seqfd, SNDCTL_SYNTH_MEMAVL, &freememory); -#endif - return 0; -} - - -void GUSOut::setPatchesToUse(int *patchesused) -{ -#ifdef HAVE_OSS_SUPPORT - int k; - for (k=0;k<256;k++) patchloaded[k]=0; - - int patchesordered[256]; //This holds the pgm used ordered by a method which - // put first the patches more oftenly used, and then the least - // In example, if a song only uses a piano and a splash cymbal, - // This is set to : 0,188,-1,-1,-1,-1 ... - patchesLoadingOrder(patchesused,patchesordered); - - // If above line doesn't work, perhaps you could try this ? : - // for (int j=0;j<256;j++) patchesordered[j]=patchesused[j]; -#ifdef GUSOUTDEBUG - printf("Patches used : \n"); - for (k=0;k<256;k++) - { - if (patchesused[k]!=-1) printf("%d,",patchesused[k]); - } - printf("\n Patches used, sorted :\n"); - for (k=0;k<256;k++) - { - if (patchesordered[k]!=-1) printf("%d,",patchesordered[k]); - } -#endif - - int i=0; - while (patchesordered[i]!=-1) - { -#ifdef GUSOUTDEBUG - printf("Load Patch : %d\n",patchesordered[i]); -#endif - loadPatch(patchesordered[i]); - i++; - } -#endif -} - -int compare_decreasing(const void *a,const void *b) -{ - struct instr_gm - { - int used; - int pgm; - }; - instr_gm *ai=(instr_gm *)a; - instr_gm *bi=(instr_gm *)b; - return ai->usedused; -} - - -void GUSOut::patchesLoadingOrder(int *patchesused,int *patchesordered) -{ - struct instr_gm - { - int used; - int pgm; - }; - - instr_gm tempmelody[128]; - instr_gm tempdrums[128]; - int i,j; - for (i=0,j=128;i<128;i++,j++) - { - tempmelody[i].used=patchesused[i]; - tempmelody[i].pgm=i; - tempdrums[i].used=patchesused[j]; - tempdrums[i].pgm=j; - } - /* SORT */ // Decreasing order (first most used patch, then less used patch) - qsort(&tempmelody[0],128,sizeof(instr_gm),compare_decreasing); - qsort(&tempdrums[0],128,sizeof(instr_gm),compare_decreasing); - - /* Once they are sorted, the result is put on patchesordered in the following - * way : If tempmelody is : M0 M1 M2 M3 ... M127 and tempdrums is : - * D0 D1 D2 D3 ... D127, the result is : - * M0 D0 M1 M2 D1 M3 M4 D2 M5 M6 D3 ... - * P0 P1 P2 P3 P4 P5 P6 P7 P8 P9 P10 ... - */ - -#ifdef GUSOUTDEBUG - for (int k=0;k<128;k++) - { - printf("%d - %d\n",tempmelody[k].used,tempmelody[k].pgm); - } - for (int k=0;k<128;k++) - { - printf("%d : %d\n",tempdrums[k].used,tempdrums[k].pgm); - } -#endif - - i=0; - int totalmelody=0; - while ((i<128)&&(tempmelody[i].used!=0)) - { - totalmelody++; - i++; - } - i=0; - int totaldrums=0; - while ((i<128)&&(tempdrums[i].used!=0)) - { - totaldrums++; - i++; - } -#ifdef GUSOUTDEBUG - printf("Totalmelody : %d,totaldrums : %d\n",totalmelody,totaldrums); -#endif - int tgt=0; - - int tm=totalmelody; - int td=totaldrums; - int cm,cd; - cm=cd=0; - if ((tm!=0)&&(td!=0)) - { - patchesordered[0]=tempmelody[0].pgm; - patchesordered[1]=tempdrums[0].pgm; - tm--;td--; - cm++;cd++; - tgt+=2; - while ((tm>0)&&(td>0)) - { - if (((tgt-1)%3)==0) - { - patchesordered[tgt]=tempdrums[cd].pgm; - cd++; - td--; - } - else - { - patchesordered[tgt]=tempmelody[cm].pgm; - cm++; - tm--; - } - tgt++; - } - } - while (tm>0) - { - patchesordered[tgt]=tempmelody[cm].pgm; - tgt++; - cm++; - tm--; - } - while (td>0) - { - patchesordered[tgt]=tempdrums[cd].pgm; - tgt++; - cd++; - td--; - } - - // Now we put as not used (-1) the rest of the array - while (tgt<256) - { - patchesordered[tgt]=-1; - tgt++; - } -} - -//char *GUSOut::GUS_patches_directory="/mnt/dosc/gravis/patches"; -const char *GUSOut::GUS_patches_directory="/usr/share/ultrasnd"; - -int GUSOut::delete_GUS_patches_directory = 0; -/* No, this doesn't delete any file :-) it's just for internal use */ diff --git a/libtdemid/gusout.cpp b/libtdemid/gusout.cpp new file mode 100644 index 000000000..96c9fb915 --- /dev/null +++ b/libtdemid/gusout.cpp @@ -0,0 +1,691 @@ +/************************************************************************** + + gusout.cpp - class GUSOut which implements support for Gravis + Ultrasound cards through a /dev/sequencer device + This file is part of LibKMid 0.9.5 + Copyright (C) 1998,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 + +***************************************************************************/ +#include "gusout.h" +#include "sndcard.h" +#include "midispec.h" +#include "gusvoices.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#ifdef HAVE_CONFIG_H +#include +#endif + +SEQ_USE_EXTBUF(); + +#ifdef HAVE_OSS_SUPPORT +struct pat_header +{ + char magic[12]; + char version[10]; + char description[60]; + unsigned char instruments; + char voices; + char channels; + unsigned short nr_waveforms; + unsigned short master_volume; + unsigned long data_size; +}; +struct sample_header +{ + char name[7]; + unsigned char fractions; + long len; + long loop_start; + long loop_end; + unsigned short base_freq; + long low_note; + long high_note; + long base_note; + short detune; + unsigned char panning; + + unsigned char envelope_rate[6]; + unsigned char envelope_offset[6]; + + unsigned char tremolo_sweep; + unsigned char tremolo_rate; + unsigned char tremolo_depth; + + unsigned char vibrato_sweep; + unsigned char vibrato_rate; + unsigned char vibrato_depth; + + char modes; + + short scale_frequency; + unsigned short scale_factor; +}; + +int get_dint(unsigned char *p) +{ + unsigned int v=0; + + for (int i=0;i<4;i++) + { + v |= (p[i] << (i*8)); + } + return (int)v; +} + +unsigned short get_word(unsigned char *p) +{ + unsigned short v=0; + + for (int i=0;i<2;i++) + v |= (*p++ << (i*8)); + return (short)v; +} + +#endif + +GUSOut::GUSOut(int d,int total) +{ + seqfd = -1; + devicetype=KMID_GUS; + device= d; + _ok=1; + + use8bit=0; + nvoices=total; + vm=new VoiceManager(nvoices); +} + +GUSOut::~GUSOut() +{ + closeDev(); + + delete vm; + if (delete_GUS_patches_directory) + { + free((char *)GUS_patches_directory); + delete_GUS_patches_directory = 0; + GUS_patches_directory="/etc"; + } +} + +void GUSOut::openDev (int sqfd) +{ + _ok=1; + seqfd = sqfd; + //vm->clearLists(); + if (seqfd==-1) + { + printfdebug("ERROR: Could not open /dev/sequencer\n"); + return; + } + +#ifdef HAVE_OSS_SUPPORT + + //seqbuf_clean(); + //ioctl(seqfd,SNDCTL_SEQ_RESET); + //ioctl(seqfd,SNDCTL_SEQ_PANIC); + + if (ioctl(seqfd, SNDCTL_SEQ_RESETSAMPLES, &device)==-1) + { + printfdebug("Error reseting gus samples. Please report\n"); + }; + use8bit=0; + totalmemory = device; + ioctl(seqfd, SNDCTL_SYNTH_MEMAVL, &totalmemory); + freememory = device; + ioctl(seqfd, SNDCTL_SYNTH_MEMAVL, &freememory); + +#endif + + +} + +void GUSOut::closeDev (void) +{ + if (!ok()) return; + vm->clearLists(); + //if (seqfd>=0) + // close(seqfd); + seqfd=-1; +} + +void GUSOut::initDev (void) +{ +#ifdef HAVE_OSS_SUPPORT + int chn; + if (!ok()) return; + uchar gm_reset[5]={0x7e, 0x7f, 0x09, 0x01, 0xf7}; + sysex(gm_reset, sizeof(gm_reset)); + for (chn=0;chn<16;chn++) + { + chnmute[chn]=0; + chnPatchChange(chn,0); + // chnPressure(chn,127); + chnPitchBender(chn, 0x00, 0x40); + chnController(chn, CTL_MAIN_VOLUME,127); + chnController(chn, CTL_EXT_EFF_DEPTH, 0); + chnController(chn, CTL_CHORUS_DEPTH, 0); + chnController(chn, 0x4a, 127); + } + + + for (int i = 0; i < nvoices; i++) + { + SEQ_CONTROL(device, i, SEQ_VOLMODE, VOL_METHOD_LINEAR); + SEQ_STOP_NOTE(device, i, vm->note(i), 64); + } + +#endif +} + + +int GUSOut::patch(int p) +{ + if (patchloaded[p]==1) return p; + printfdebug("Not loaded %d!\n",p); + p=0; + while ((p<256)&&(patchloaded[p]==0)) p++; + return p; +} + +void GUSOut::noteOn (uchar chn, uchar note, uchar vel) +{ + if (vel==0) + { + noteOff(chn,note,vel); + } + else + { + if (chn==PERCUSSION_CHANNEL) + { + if (patchloaded[note+128]==0) return; + else + if (patchloaded[chnpatch[chn]]==0) return; + }; + int v=vm->allocateVoice(chn,note); + int p; + if (chn==PERCUSSION_CHANNEL) + SEQ_SET_PATCH(device,v ,p=patch(note+128)) + else + SEQ_SET_PATCH(device,v ,p=map->patch(chn,chnpatch[chn])); + SEQ_BENDER(device, v, chnbender[chn]); + + SEQ_START_NOTE(device, v, note, vel); + // SEQ_CONTROL(device, v, CTL_MAIN_VOLUME, chncontroller[chn][CTL_MAIN_VOLUME]); + SEQ_CHN_PRESSURE(device, v , chnpressure[chn]); + } + + printfdebug("Note ON >\t chn : %d\tnote : %d\tvel: %d\n",chn,note,vel); +} + +void GUSOut::noteOff (uchar chn, uchar note, uchar vel) +{ + int i; + vm->initSearch(); + while ((i=vm->search(chn,note))!=-1) + { + SEQ_STOP_NOTE(device, i, note, vel); + vm->deallocateVoice(i); + } + +#ifdef GUSOUTDEBUG + printf("Note OFF >\t chn : %d\tnote : %d\tvel: %d\n",chn,note,vel); +#endif +} + +void GUSOut::keyPressure (uchar chn, uchar note, uchar vel) +{ + int i; + vm->initSearch(); + while ((i=vm->search(chn,note))!=-1) + SEQ_KEY_PRESSURE(device, i, note,vel); +} + +void GUSOut::chnPatchChange (uchar chn, uchar patch) +{ + if (chn==PERCUSSION_CHANNEL) return; + int i; + vm->initSearch(); + while ((i=vm->search(chn))!=-1) + SEQ_SET_PATCH(device,i,map->patch(chn,patch)); + chnpatch[chn]=patch; + +} + +void GUSOut::chnPressure (uchar /*chn*/, uchar /*vel*/) +{ + /* int i; + vm->initSearch(); + while ((i=vm->search(chn))!=-1) + SEQ_CHN_PRESSURE(device, i , vel); + chnpressure[chn]=vel; + */ +} + +void GUSOut::chnPitchBender(uchar chn,uchar lsb, uchar msb) +{ + chnbender[chn]=((int)msb<<7) | (lsb & 0x7F); + + int i; + vm->initSearch(); + while ((i=vm->search(chn))!=-1) + SEQ_BENDER(device, i, chnbender[chn]); +} + +void GUSOut::chnController (uchar chn, uchar ctl, uchar v) +{ + if ((ctl==11)||(ctl==7)) + { + v=(v*volumepercentage)/100; + if (v>127) v=127; + }; + + int i; + vm->initSearch(); + while ((i=vm->search(chn))!=-1) + SEQ_CONTROL(device, i, ctl, v); + + chncontroller[chn][ctl]=v; +} + +void GUSOut::sysex(uchar *, ulong ) +{ + +} + +void GUSOut::setGUSPatchesDirectory(const char *dir) +{ + if ((dir==NULL)||(dir[0]==0)) return; + if (delete_GUS_patches_directory) + free((char *)GUS_patches_directory); + + GUS_patches_directory = strdup(dir); + delete_GUS_patches_directory=1; +} + +const char *GUSOut::patchName(int pgm) +{ + return GUS_voice_names[pgm]; +} + + +int GUSOut::loadPatch(int pgm) +{ +#ifdef HAVE_OSS_SUPPORT + struct pat_header header; + struct sample_header sample; + if (patchloaded[pgm]==1) + { +#ifdef GUSOUTDEBUG + printf("Trying to reload a patch. This should never happen, please report.\n"); +#endif + return 0; + } + if ((patchName(pgm)==NULL)||((patchName(pgm))[0]==0)) + { +#ifdef GUSOUTDEBUG + printf("Couldn't guess patch name for patch number %d\n",pgm); +#endif + return -1; + } + char *s=new char[strlen(GUS_patches_directory)+strlen(patchName(pgm))+10]; + if (s==NULL) return -1; + sprintf(s,"%s/%s.pat",GUS_patches_directory,patchName(pgm)); +#ifdef GUSOUTDEBUG + printf("Loading patch : %s\n",s); +#endif + struct patch_info *patch=NULL; + struct stat info; + if (stat(s, &info)==-1) + { +#ifdef GUSOUTDEBUG + printf("File %s doesn't exist\n",s); +#endif + return -1; + } + + FILE *fh=fopen(s,"rb"); + if (fh==NULL) + { +#ifdef GUSOUTDEBUG + printf("Couldn't open patch %s\n",s); +#endif + return -1; + } + + unsigned char tmp[256]; + if (fread(tmp,1,0xef,fh)!=0xef) + { + fclose(fh); +#ifdef GUSOUTDEBUG + printf("Short file ! \n"); +#endif + return -1; + } + memcpy ((char *) &header, tmp, sizeof (header)); + + if (strncmp(header.magic,"GF1PATCH110",12)!=0) + { +#ifdef GUSOUTDEBUG + printf("File %s is corrupted or it isn't a patch file\n",s); +#endif + return -1; + } + if (strncmp(header.version,"ID#000002",10)!=0) + { +#ifdef GUSOUTDEBUG + printf("File %s's version is not supported\n",s); +#endif + return -1; + } + unsigned short nWaves= *(unsigned short *)&tmp[85]; +#ifdef GUSOUTDEBUG + unsigned short masterVolume= *(unsigned short *)&tmp[87]; + printf("nWaves: %d\n",nWaves); + printf("masterVolume : %d\n",masterVolume); +#endif + + unsigned short i; + int offset=0xef; + for (i=0;ikey = GUS_PATCH; + patch->device_no = device; + patch->instr_no = pgm; + patch->mode = sample.modes | WAVE_TREMOLO | WAVE_VIBRATO | WAVE_SCALE; + patch->len = sample.len; + patch->loop_start = sample.loop_start; + patch->loop_end = sample.loop_end; + patch->base_note = sample.base_note; + patch->high_note = sample.high_note; + patch->low_note = sample.low_note; + patch->base_freq = sample.base_freq; + patch->detuning = sample.detune; + patch->panning = (sample.panning - 7) * 16; + + memcpy (patch->env_rate, sample.envelope_rate, 6); + memcpy (patch->env_offset, sample.envelope_offset, 6); + + patch->tremolo_sweep = sample.tremolo_sweep; + patch->tremolo_rate = sample.tremolo_rate; + patch->tremolo_depth = sample.tremolo_depth; + + patch->vibrato_sweep = sample.vibrato_sweep; + patch->vibrato_rate = sample.vibrato_rate; + patch->vibrato_depth = sample.vibrato_depth; + + patch->scale_frequency = sample.scale_frequency; + patch->scale_factor = sample.scale_factor; + + patch->volume = header.master_volume; + + if (fseek (fh, offset, 0) == -1) + { + fclose(fh); + return -1; + } + + if ((long)fread (patch->data, 1,sample.len,fh) != sample.len) + { +#ifdef GUSOUTDEBUG + printf ("Short file\n"); +#endif + return -1; + } + + SEQ_WRPATCH (patch, sizeof (*patch) + sample.len); + + offset = offset + sample.len; + + } + patchloaded[pgm]=1; + + fclose(fh); + free(patch); // Shouldn't this 'free' be within the 'for' loop ? + delete s; + freememory = device; + ioctl(seqfd, SNDCTL_SYNTH_MEMAVL, &freememory); +#endif + return 0; +} + + +void GUSOut::setPatchesToUse(int *patchesused) +{ +#ifdef HAVE_OSS_SUPPORT + int k; + for (k=0;k<256;k++) patchloaded[k]=0; + + int patchesordered[256]; //This holds the pgm used ordered by a method which + // put first the patches more oftenly used, and then the least + // In example, if a song only uses a piano and a splash cymbal, + // This is set to : 0,188,-1,-1,-1,-1 ... + patchesLoadingOrder(patchesused,patchesordered); + + // If above line doesn't work, perhaps you could try this ? : + // for (int j=0;j<256;j++) patchesordered[j]=patchesused[j]; +#ifdef GUSOUTDEBUG + printf("Patches used : \n"); + for (k=0;k<256;k++) + { + if (patchesused[k]!=-1) printf("%d,",patchesused[k]); + } + printf("\n Patches used, sorted :\n"); + for (k=0;k<256;k++) + { + if (patchesordered[k]!=-1) printf("%d,",patchesordered[k]); + } +#endif + + int i=0; + while (patchesordered[i]!=-1) + { +#ifdef GUSOUTDEBUG + printf("Load Patch : %d\n",patchesordered[i]); +#endif + loadPatch(patchesordered[i]); + i++; + } +#endif +} + +int compare_decreasing(const void *a,const void *b) +{ + struct instr_gm + { + int used; + int pgm; + }; + instr_gm *ai=(instr_gm *)a; + instr_gm *bi=(instr_gm *)b; + return ai->usedused; +} + + +void GUSOut::patchesLoadingOrder(int *patchesused,int *patchesordered) +{ + struct instr_gm + { + int used; + int pgm; + }; + + instr_gm tempmelody[128]; + instr_gm tempdrums[128]; + int i,j; + for (i=0,j=128;i<128;i++,j++) + { + tempmelody[i].used=patchesused[i]; + tempmelody[i].pgm=i; + tempdrums[i].used=patchesused[j]; + tempdrums[i].pgm=j; + } + /* SORT */ // Decreasing order (first most used patch, then less used patch) + qsort(&tempmelody[0],128,sizeof(instr_gm),compare_decreasing); + qsort(&tempdrums[0],128,sizeof(instr_gm),compare_decreasing); + + /* Once they are sorted, the result is put on patchesordered in the following + * way : If tempmelody is : M0 M1 M2 M3 ... M127 and tempdrums is : + * D0 D1 D2 D3 ... D127, the result is : + * M0 D0 M1 M2 D1 M3 M4 D2 M5 M6 D3 ... + * P0 P1 P2 P3 P4 P5 P6 P7 P8 P9 P10 ... + */ + +#ifdef GUSOUTDEBUG + for (int k=0;k<128;k++) + { + printf("%d - %d\n",tempmelody[k].used,tempmelody[k].pgm); + } + for (int k=0;k<128;k++) + { + printf("%d : %d\n",tempdrums[k].used,tempdrums[k].pgm); + } +#endif + + i=0; + int totalmelody=0; + while ((i<128)&&(tempmelody[i].used!=0)) + { + totalmelody++; + i++; + } + i=0; + int totaldrums=0; + while ((i<128)&&(tempdrums[i].used!=0)) + { + totaldrums++; + i++; + } +#ifdef GUSOUTDEBUG + printf("Totalmelody : %d,totaldrums : %d\n",totalmelody,totaldrums); +#endif + int tgt=0; + + int tm=totalmelody; + int td=totaldrums; + int cm,cd; + cm=cd=0; + if ((tm!=0)&&(td!=0)) + { + patchesordered[0]=tempmelody[0].pgm; + patchesordered[1]=tempdrums[0].pgm; + tm--;td--; + cm++;cd++; + tgt+=2; + while ((tm>0)&&(td>0)) + { + if (((tgt-1)%3)==0) + { + patchesordered[tgt]=tempdrums[cd].pgm; + cd++; + td--; + } + else + { + patchesordered[tgt]=tempmelody[cm].pgm; + cm++; + tm--; + } + tgt++; + } + } + while (tm>0) + { + patchesordered[tgt]=tempmelody[cm].pgm; + tgt++; + cm++; + tm--; + } + while (td>0) + { + patchesordered[tgt]=tempdrums[cd].pgm; + tgt++; + cd++; + td--; + } + + // Now we put as not used (-1) the rest of the array + while (tgt<256) + { + patchesordered[tgt]=-1; + tgt++; + } +} + +//char *GUSOut::GUS_patches_directory="/mnt/dosc/gravis/patches"; +const char *GUSOut::GUS_patches_directory="/usr/share/ultrasnd"; + +int GUSOut::delete_GUS_patches_directory = 0; +/* No, this doesn't delete any file :-) it's just for internal use */ diff --git a/libtdemid/libtdemid.cc b/libtdemid/libtdemid.cc deleted file mode 100644 index 04a0dac0d..000000000 --- a/libtdemid/libtdemid.cc +++ /dev/null @@ -1,263 +0,0 @@ -/************************************************************************** - - libtdemid.cc - class KMidSimpleAPI that makes it easy to use libtdemid - and a C wrapper. - This file is part of LibKMid 0.9.5 - Copyright (C) 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 - -***************************************************************************/ - -#include "libtdemid.h" -#include -#include -#include -#include -#include -#include - -#include "deviceman.h" -#include "player.h" -#include "midimapper.h" - -struct kMidData kMid; - -int KMidSimpleAPI::kMidInit(void) -{ - kMid.midi = new DeviceManager(); - if ( kMid.midi == 0L ) return 1; - kMid.midi->initManager(); - if (!kMid.midi->ok()) return 1; - - kMid.pctlsmID=shmget(getpid(),sizeof(PlayerController),0600 | IPC_CREAT); - if (kMid.pctlsmID==-1) return 1; - kMid.pctl=(PlayerController *)shmat(kMid.pctlsmID,NULL,0); - if (kMid.pctl==NULL) return 1; - - kMid.player=new MidiPlayer(kMid.midi,kMid.pctl); - if ( kMid.player == 0L ) - { - delete kMid.midi; - return 1; - } - - kMid.player->setParseSong(false); - - kMid.pctl->message=0; - kMid.pctl->gm=1; - kMid.pctl->error=0; - kMid.pctl->ratioTempo=1.0; - kMid.pctl->tempo=500000; - kMid.pctl->volumepercentage=100; - for (int i=0;i<16;i++) - { - kMid.pctl->forcepgm[i]=0; - kMid.pctl->pgm[i]=0; - } - - return 0; -} - -int KMidSimpleAPI::kMidLoad(const char *filename) -{ - if (kMidDevices()==0) return 0; - return kMid.player->loadSong(filename); -} - -int KMidSimpleAPI::kMidPlay(int loop) -{ - if (kMidDevices()==0) return 4; - if (!kMid.player->isSongLoaded()) return 1; - if (kMid.pctl->playing==1) return 2; - if (kMid.midi->checkInit()==-1) return 3; - kMid.pctl->message=0; - kMid.pctl->playing=0; - kMid.pctl->finished=0; - kMid.pctl->error=0; - kMid.pctl->SPEVplayed=0; - kMid.pctl->SPEVprocessed=0; - kMid.pctl->millisecsPlayed=0; - if ((kMid.pid=fork())==0) - { - if (loop) - { - while (1) - { - kMid.player->play(); - if (kMid.pctl->error) return 5; - kMid.pctl->message=0; - kMid.pctl->playing=0; - kMid.pctl->finished=0; - kMid.pctl->error=0; - kMid.pctl->SPEVplayed=0; - kMid.pctl->SPEVprocessed=0; - kMid.pctl->millisecsPlayed=0; - } - - } else { - kMid.player->play(); - if (kMid.pctl->error) return 5; - } - _exit(0); - } else return 4; - return 0; -} - -int KMidSimpleAPI::kMidStop(void) -{ - if (kMidDevices()==0) return 4; - if (kMid.pctl->playing==0) return 1; - if (kMid.pid!=0) - { - kill(kMid.pid,SIGTERM); - waitpid(kMid.pid, NULL, 0); - kMid.pid=0; - } else return 2; - - kMid.pctl->playing=0; - return 0; -} - -void KMidSimpleAPI::kMidDestruct(void) -{ - delete kMid.midi; - kMid.midi=0L; - delete kMid.player; - kMid.player=0L; - delete kMid.map; - shmdt((char *)kMid.pctl); - shmctl(kMid.pctlsmID, IPC_RMID, 0L); -} - -int KMidSimpleAPI::kMidIsPlaying(void) -{ - return kMid.pctl->playing; -} - -int KMidSimpleAPI::kMidDevices(void) -{ - return kMid.midi->midiPorts()+kMid.midi->synthDevices(); -} - -const char * KMidSimpleAPI::kMidName(int i) -{ - return kMid.midi->name(i); -} - -const char * KMidSimpleAPI::kMidType(int i) -{ - return kMid.midi->type(i); -} - -void KMidSimpleAPI::kMidSetDevice(int i) -{ - kMid.midi->setDefaultDevice(i); -} - -void KMidSimpleAPI::kMidSetMidiMapper(const char *mapfilename) -{ - if (kMidDevices()==0) return; - kMid.map=new MidiMapper(mapfilename); - if ((kMid.map->ok() == 0L)||(!kMid.map->ok())) return; - kMid.midi->setMidiMap(kMid.map); -} - -const char *KMidSimpleAPI::kMidVersion(void) -{ - return "0.9.5"; -} - -const char *KMidSimpleAPI::kMidCopyright(void) -{ - return "LibKMid 0.9.5 (C)1997-2000 Antonio Larrosa Jimenez .Malaga(es)"; -} - -/* * * * * * - - Under this line (------) there's only a C wrapper for the KMidSimpleAPI class - -* * * * * */ - - -int kMidInit(void) -{ - return KMidSimpleAPI::kMidInit(); -} - -int kMidLoad(const char *filename) -{ - return KMidSimpleAPI::kMidLoad(filename); -} - -int kMidPlay(void) -{ - return KMidSimpleAPI::kMidPlay(); -} - -int kMidStop(void) -{ - return KMidSimpleAPI::kMidStop(); -} - -void kMidDestruct(void) -{ - KMidSimpleAPI::kMidDestruct(); -} - -int kMidIsPlaying(void) -{ - return KMidSimpleAPI::kMidIsPlaying(); -} - -int kMidDevices(void) -{ - return KMidSimpleAPI::kMidDevices(); -} - -const char *kMidName(int i) -{ - return KMidSimpleAPI::kMidName(i); -} - -const char *kMidType(int i) -{ - return KMidSimpleAPI::kMidType(i); -} - -void kMidSetDevice(int i) -{ - KMidSimpleAPI::kMidSetDevice(i); -} - -void kMidSetMidiMapper(const char *mapfilename) -{ - KMidSimpleAPI::kMidSetMidiMapper(mapfilename); -} - -const char *kMidVersion(void) -{ - return KMidSimpleAPI::kMidVersion(); -} - -const char *kMidCopyright(void) -{ - return KMidSimpleAPI::kMidCopyright(); -} - diff --git a/libtdemid/libtdemid.cpp b/libtdemid/libtdemid.cpp new file mode 100644 index 000000000..fcc75d3e5 --- /dev/null +++ b/libtdemid/libtdemid.cpp @@ -0,0 +1,263 @@ +/************************************************************************** + + libtdemid.cpp - class KMidSimpleAPI that makes it easy to use libtdemid + and a C wrapper. + This file is part of LibKMid 0.9.5 + Copyright (C) 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 + +***************************************************************************/ + +#include "libtdemid.h" +#include +#include +#include +#include +#include +#include + +#include "deviceman.h" +#include "player.h" +#include "midimapper.h" + +struct kMidData kMid; + +int KMidSimpleAPI::kMidInit(void) +{ + kMid.midi = new DeviceManager(); + if ( kMid.midi == 0L ) return 1; + kMid.midi->initManager(); + if (!kMid.midi->ok()) return 1; + + kMid.pctlsmID=shmget(getpid(),sizeof(PlayerController),0600 | IPC_CREAT); + if (kMid.pctlsmID==-1) return 1; + kMid.pctl=(PlayerController *)shmat(kMid.pctlsmID,NULL,0); + if (kMid.pctl==NULL) return 1; + + kMid.player=new MidiPlayer(kMid.midi,kMid.pctl); + if ( kMid.player == 0L ) + { + delete kMid.midi; + return 1; + } + + kMid.player->setParseSong(false); + + kMid.pctl->message=0; + kMid.pctl->gm=1; + kMid.pctl->error=0; + kMid.pctl->ratioTempo=1.0; + kMid.pctl->tempo=500000; + kMid.pctl->volumepercentage=100; + for (int i=0;i<16;i++) + { + kMid.pctl->forcepgm[i]=0; + kMid.pctl->pgm[i]=0; + } + + return 0; +} + +int KMidSimpleAPI::kMidLoad(const char *filename) +{ + if (kMidDevices()==0) return 0; + return kMid.player->loadSong(filename); +} + +int KMidSimpleAPI::kMidPlay(int loop) +{ + if (kMidDevices()==0) return 4; + if (!kMid.player->isSongLoaded()) return 1; + if (kMid.pctl->playing==1) return 2; + if (kMid.midi->checkInit()==-1) return 3; + kMid.pctl->message=0; + kMid.pctl->playing=0; + kMid.pctl->finished=0; + kMid.pctl->error=0; + kMid.pctl->SPEVplayed=0; + kMid.pctl->SPEVprocessed=0; + kMid.pctl->millisecsPlayed=0; + if ((kMid.pid=fork())==0) + { + if (loop) + { + while (1) + { + kMid.player->play(); + if (kMid.pctl->error) return 5; + kMid.pctl->message=0; + kMid.pctl->playing=0; + kMid.pctl->finished=0; + kMid.pctl->error=0; + kMid.pctl->SPEVplayed=0; + kMid.pctl->SPEVprocessed=0; + kMid.pctl->millisecsPlayed=0; + } + + } else { + kMid.player->play(); + if (kMid.pctl->error) return 5; + } + _exit(0); + } else return 4; + return 0; +} + +int KMidSimpleAPI::kMidStop(void) +{ + if (kMidDevices()==0) return 4; + if (kMid.pctl->playing==0) return 1; + if (kMid.pid!=0) + { + kill(kMid.pid,SIGTERM); + waitpid(kMid.pid, NULL, 0); + kMid.pid=0; + } else return 2; + + kMid.pctl->playing=0; + return 0; +} + +void KMidSimpleAPI::kMidDestruct(void) +{ + delete kMid.midi; + kMid.midi=0L; + delete kMid.player; + kMid.player=0L; + delete kMid.map; + shmdt((char *)kMid.pctl); + shmctl(kMid.pctlsmID, IPC_RMID, 0L); +} + +int KMidSimpleAPI::kMidIsPlaying(void) +{ + return kMid.pctl->playing; +} + +int KMidSimpleAPI::kMidDevices(void) +{ + return kMid.midi->midiPorts()+kMid.midi->synthDevices(); +} + +const char * KMidSimpleAPI::kMidName(int i) +{ + return kMid.midi->name(i); +} + +const char * KMidSimpleAPI::kMidType(int i) +{ + return kMid.midi->type(i); +} + +void KMidSimpleAPI::kMidSetDevice(int i) +{ + kMid.midi->setDefaultDevice(i); +} + +void KMidSimpleAPI::kMidSetMidiMapper(const char *mapfilename) +{ + if (kMidDevices()==0) return; + kMid.map=new MidiMapper(mapfilename); + if ((kMid.map->ok() == 0L)||(!kMid.map->ok())) return; + kMid.midi->setMidiMap(kMid.map); +} + +const char *KMidSimpleAPI::kMidVersion(void) +{ + return "0.9.5"; +} + +const char *KMidSimpleAPI::kMidCopyright(void) +{ + return "LibKMid 0.9.5 (C)1997-2000 Antonio Larrosa Jimenez .Malaga(es)"; +} + +/* * * * * * + + Under this line (------) there's only a C wrapper for the KMidSimpleAPI class + +* * * * * */ + + +int kMidInit(void) +{ + return KMidSimpleAPI::kMidInit(); +} + +int kMidLoad(const char *filename) +{ + return KMidSimpleAPI::kMidLoad(filename); +} + +int kMidPlay(void) +{ + return KMidSimpleAPI::kMidPlay(); +} + +int kMidStop(void) +{ + return KMidSimpleAPI::kMidStop(); +} + +void kMidDestruct(void) +{ + KMidSimpleAPI::kMidDestruct(); +} + +int kMidIsPlaying(void) +{ + return KMidSimpleAPI::kMidIsPlaying(); +} + +int kMidDevices(void) +{ + return KMidSimpleAPI::kMidDevices(); +} + +const char *kMidName(int i) +{ + return KMidSimpleAPI::kMidName(i); +} + +const char *kMidType(int i) +{ + return KMidSimpleAPI::kMidType(i); +} + +void kMidSetDevice(int i) +{ + KMidSimpleAPI::kMidSetDevice(i); +} + +void kMidSetMidiMapper(const char *mapfilename) +{ + KMidSimpleAPI::kMidSetMidiMapper(mapfilename); +} + +const char *kMidVersion(void) +{ + return KMidSimpleAPI::kMidVersion(); +} + +const char *kMidCopyright(void) +{ + return KMidSimpleAPI::kMidCopyright(); +} + diff --git a/libtdemid/midfile.cc b/libtdemid/midfile.cc deleted file mode 100644 index f8222b3f8..000000000 --- a/libtdemid/midfile.cc +++ /dev/null @@ -1,460 +0,0 @@ -/************************************************************************** - - midfile.cc - function which reads a midi file,and creates the track classes - 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 - -***************************************************************************/ -#include "midfile.h" -#include -#include -#include -#include -#include "sndcard.h" -#include "midispec.h" -#include "mt32togm.h" -#include "sys/stat.h" -#include - -#include -#include - -int fsearch(FILE *fh,const char *text,long *ptr); - -/* This function gives the metronome tempo, from a tempo data as found in - a midi file */ -double tempoToMetronomeTempo(ulong x) -{ - return 60/((double)x/1000000); -} - -double metronomeTempoToTempo(ulong x) -{ - return ((double)60*x)/1000000; -} - -int uncompressFile(const char *gzname, char *tmpname) - // Returns 0 if OK, 1 if error (tmpname not set) -{ - TQString cmd("gzip -dc " + TDEProcess::quote(gzname)); - FILE *infile = popen( TQFile::encodeName(cmd).data(), "r"); - if (infile==NULL) { - fprintf(stderr,"ERROR : popen failed : %s\n",TQFile::encodeName(cmd).data()); - return 1; - } - strcpy(tmpname, "/tmp/KMid.XXXXXXXXXX"); - int fd = mkstemp(tmpname); - if (fd == -1) - { - pclose(infile); - return 1; - } - FILE *outfile= fdopen(fd,"wb"); - if (outfile==NULL) - { - pclose(infile); - return 1; - } - int n=getc(infile); - if (n==EOF) - { - pclose(infile); - fclose(outfile); - unlink(tmpname); - return 1; - } - fputc(n,outfile); - int buf[BUFSIZ]; - n = fread(buf, 1, BUFSIZ, infile); - while (n>0) - { - fwrite(buf, 1, n, outfile); - n = fread(buf, 1, BUFSIZ, infile); - } - - pclose(infile); - - //if (pclose(infile) != 0) fprintf(stderr,"Error : pclose failed\n"); - // Is it right for pclose to always fail ? - - fclose(outfile); - return 0; -} - -MidiTrack **readMidiFile( const char *name, MidiFileInfo *info, int &ok) -{ - ok=1; - MidiTrack **tracks; - - struct stat buf; - if (stat(name,&buf) || !S_ISREG(buf.st_mode)) - { - fprintf(stderr,"ERROR: %s is not a regular file\n",name); - ok=-6; - return NULL; - } - - FILE *fh=fopen(name,"rb"); - if (fh==NULL) - { - fprintf(stderr,"ERROR: Can't open file %s\n",name); - ok=-1; - return NULL; - } - char text[4]; - text[0] = 0; - fread(text,1,4,fh); - if ((strncmp(text,"MThd",4)!=0)&&(strcmp(&name[strlen(name)-3],".gz")==0)) - { - fclose(fh); - char tempname[200]; - fprintf(stderr,"Trying to open zipped midi file...\n"); - if (uncompressFile(name,tempname)!=0) - { - fprintf(stderr,"ERROR: %s is not a (zipped) midi file\n",name); - ok=-2; - return NULL; - } - fh=fopen(tempname,"rb"); - fread(text,1,4,fh); - unlink(tempname); - } - - if (strncmp(text,"MThd",4)!=0) - { - fseek(fh,0,SEEK_SET); - long pos; - if (fsearch(fh,"MThd",&pos)==0) - { - fclose(fh); - fprintf(stderr,"ERROR: %s is not a midi file.\n",name); - ok=-2; - return NULL; - } - fseek(fh,pos,SEEK_SET); - fread(text,1,4,fh); - } - long header_size=readLong(fh); - info->format=readShort(fh); - info->ntracks=readShort(fh); - info->ticksPerCuarterNote=readShort(fh); - if (info->ticksPerCuarterNote<0) - { - fprintf(stderr,"ERROR: Ticks per cuarter note is negative !\n"); - fprintf(stderr,"Please report this error to : larrosa@kde.org\n"); - fclose(fh); - ok=-3; - return NULL; - } - if (header_size>6) fseek(fh,header_size-6,SEEK_CUR); - tracks=new MidiTrack*[info->ntracks]; - if (tracks==NULL) - { - fprintf(stderr,"ERROR: Not enough memory\n"); - fclose(fh); - ok=-4; - return NULL; - } - int i=0; - while (intracks) - { - fread(text,1,4,fh); - if (strncmp(text,"MTrk",4)!=0) - { - fprintf(stderr,"ERROR: Not a well built midi file\n"); - fprintf(stderr,"%s",text); - fclose(fh); - ok=-5; - return NULL; - } - tracks[i]=new MidiTrack(fh,info->ticksPerCuarterNote,i); - if (tracks[i]==NULL) - { - fprintf(stderr,"ERROR: Not enough memory"); - fclose(fh); - ok=-4; - return NULL; - } - i++; - } - - fclose(fh); - - return tracks; - -} - -void parseInfoData(MidiFileInfo *info,MidiTrack **tracks,float ratioTempo) -{ - - info->ticksTotal=0; - info->millisecsTotal=0.0; - info->ticksPlayed=0; - int i; - for (i=0;i<256;i++) - { - info->patchesUsed[i]=0; - } - - int parsing=1; - int trk,minTrk; - ulong tempo=(ulong)(500000 * ratioTempo); - -#ifdef MIDFILEDEBUG - printf("Parsing 1 ...\n"); -#endif - - int pgminchannel[16]; - for (i=0;i<16;i++) - { - pgminchannel[i]=0; - } - - int j; - for (i=0;intracks;i++) - { - tracks[i]->init(); - tracks[i]->changeTempo(tempo); - } - double prevms=0; - double minTime=0; - double maxTime; - MidiEvent *ev=new MidiEvent; - while (parsing) - { - prevms=minTime; - trk=0; - minTrk=0; - maxTime=minTime + 2 * 60000L; - minTime=maxTime; - while (trkntracks) - { - if (tracks[trk]->absMsOfNextEvent()absMsOfNextEvent(); - } - trk++; - } - if ((minTime==maxTime)) - { - parsing=0; -#ifdef MIDFILEDEBUG - printf("END of parsing\n"); -#endif - } - else - { - trk=0; - while (trkntracks) - { - tracks[trk]->currentMs(minTime); - trk++; - } - } - trk=minTrk; - tracks[trk]->readEvent(ev); - - switch (ev->command) - { - case (MIDI_NOTEON) : - if (ev->chn!=PERCUSSION_CHANNEL) - info->patchesUsed[pgminchannel[ev->chn]]++; - else - info->patchesUsed[ev->note+128]++; - break; - case (MIDI_PGM_CHANGE) : - pgminchannel[ev->chn]=(ev->patch); - break; - case (MIDI_SYSTEM_PREFIX) : - if (((ev->command|ev->chn)==META_EVENT)&&(ev->d1==ME_SET_TEMPO)) - { - tempo=(ulong)(((ev->data[0]<<16)|(ev->data[1]<<8)|(ev->data[2])) * ratioTempo); - for (j=0;jntracks;j++) - { - tracks[j]->changeTempo(tempo); - } - } - break; - } - } - - delete ev; - info->millisecsTotal=prevms; - - for (i=0;intracks;i++) - { - tracks[i]->init(); - } - -#ifdef MIDFILEDEBUG - printf("info.ticksTotal = %ld \n",info->ticksTotal); - printf("info.ticksPlayed= %ld \n",info->ticksPlayed); - printf("info.millisecsTotal = %g \n",info->millisecsTotal); - printf("info.TicksPerCN = %d \n",info->ticksPerCuarterNote); -#endif - -} - - -void parsePatchesUsed(MidiTrack **tracks,MidiFileInfo *info,int gm) -{ - int i; - for (i=0;i<256;i++) - { - info->patchesUsed[i]=0; - } - int parsing=1; - int trk,minTrk; - ulong tempo=500000; - -#ifdef MIDFILEDEBUG - printf("Parsing for patches ...\n"); -#endif - - int j; - for (i=0;intracks;i++) - { - tracks[i]->init(); - } - double prevms=0; - double minTime=0; - double maxTime; - ulong tmp; - MidiEvent *ev=new MidiEvent; - int pgminchannel[16]; - for (i=0;i<16;i++) - { - pgminchannel[i]=0; - } - - while (parsing) - { - prevms=minTime; - trk=0; - minTrk=0; - maxTime=minTime + 2 * 60000L; - minTime=maxTime; - while (trkntracks) - { - if (tracks[trk]->absMsOfNextEvent()absMsOfNextEvent(); - } - trk++; - } - if ((minTime==maxTime)) - { - parsing=0; -#ifdef MIDFILEDEBUG - printf("END of parsing for patches\n"); -#endif - } - else - { - trk=0; - while (trkntracks) - { - tracks[trk]->currentMs(minTime); - trk++; - } - } - trk=minTrk; - tracks[trk]->readEvent(ev); - switch (ev->command) - { - case (MIDI_NOTEON) : - if (ev->chn!=PERCUSSION_CHANNEL) - info->patchesUsed[pgminchannel[ev->chn]]++; - else - info->patchesUsed[ev->note+128]++; - break; - case (MIDI_PGM_CHANGE) : - pgminchannel[ev->chn]=(gm==1)?(ev->patch):(MT32toGM[ev->patch]); - break; - case (MIDI_SYSTEM_PREFIX) : - if (((ev->command|ev->chn)==META_EVENT)&&(ev->d1==ME_SET_TEMPO)) - { - if (tempoToMetronomeTempo(tmp=((ev->data[0]<<16)|(ev->data[1]<<8)|(ev->data[2])))>=8) - { - tempo=tmp; - // printf("setTempo %ld\n",tempo); - for (j=0;jntracks;j++) - { - tracks[j]->changeTempo(tempo); - } - } - } - break; - } - } - - delete ev; - - for (i=0;intracks;i++) - { - tracks[i]->init(); - } - -} - -int fsearch(FILE *fh,const char *text,long *ptr) - // Search for "text" through the fh file and then returns : - // text MUST BE smaller than 256 characters - // 0 if not was found - // 1 if it was found and in ptr (if !=NULL) the position where text begins. -{ - if ((text==NULL)||(text[0]==0)) return 0; - char buf[1024]; - char tmp[256]; - long pos; - int l=strlen(text); - int i,k,r; - while (!feof(fh)) - { - pos=ftell(fh); - k=fread(buf,1,1024,fh); - i=0; - while (i=l) - r=strncmp(text,&buf[i],l); - else - { - fseek(fh,pos+i,SEEK_SET); - if (fread(tmp,1,l,fh)<(uint)l) return 0; - fseek(fh,pos+k,SEEK_SET); - r=strncmp(text,tmp,l); - } - if (r==0) - { - if (ptr!=NULL) *ptr=pos+i; - return 1; - } - } - i++; - } - } - return 0; -} diff --git a/libtdemid/midfile.cpp b/libtdemid/midfile.cpp new file mode 100644 index 000000000..bfeb056f0 --- /dev/null +++ b/libtdemid/midfile.cpp @@ -0,0 +1,460 @@ +/************************************************************************** + + midfile.cpp - function which reads a midi file,and creates the track classes + 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 + +***************************************************************************/ +#include "midfile.h" +#include +#include +#include +#include +#include "sndcard.h" +#include "midispec.h" +#include "mt32togm.h" +#include "sys/stat.h" +#include + +#include +#include + +int fsearch(FILE *fh,const char *text,long *ptr); + +/* This function gives the metronome tempo, from a tempo data as found in + a midi file */ +double tempoToMetronomeTempo(ulong x) +{ + return 60/((double)x/1000000); +} + +double metronomeTempoToTempo(ulong x) +{ + return ((double)60*x)/1000000; +} + +int uncompressFile(const char *gzname, char *tmpname) + // Returns 0 if OK, 1 if error (tmpname not set) +{ + TQString cmd("gzip -dc " + TDEProcess::quote(gzname)); + FILE *infile = popen( TQFile::encodeName(cmd).data(), "r"); + if (infile==NULL) { + fprintf(stderr,"ERROR : popen failed : %s\n",TQFile::encodeName(cmd).data()); + return 1; + } + strcpy(tmpname, "/tmp/KMid.XXXXXXXXXX"); + int fd = mkstemp(tmpname); + if (fd == -1) + { + pclose(infile); + return 1; + } + FILE *outfile= fdopen(fd,"wb"); + if (outfile==NULL) + { + pclose(infile); + return 1; + } + int n=getc(infile); + if (n==EOF) + { + pclose(infile); + fclose(outfile); + unlink(tmpname); + return 1; + } + fputc(n,outfile); + int buf[BUFSIZ]; + n = fread(buf, 1, BUFSIZ, infile); + while (n>0) + { + fwrite(buf, 1, n, outfile); + n = fread(buf, 1, BUFSIZ, infile); + } + + pclose(infile); + + //if (pclose(infile) != 0) fprintf(stderr,"Error : pclose failed\n"); + // Is it right for pclose to always fail ? + + fclose(outfile); + return 0; +} + +MidiTrack **readMidiFile( const char *name, MidiFileInfo *info, int &ok) +{ + ok=1; + MidiTrack **tracks; + + struct stat buf; + if (stat(name,&buf) || !S_ISREG(buf.st_mode)) + { + fprintf(stderr,"ERROR: %s is not a regular file\n",name); + ok=-6; + return NULL; + } + + FILE *fh=fopen(name,"rb"); + if (fh==NULL) + { + fprintf(stderr,"ERROR: Can't open file %s\n",name); + ok=-1; + return NULL; + } + char text[4]; + text[0] = 0; + fread(text,1,4,fh); + if ((strncmp(text,"MThd",4)!=0)&&(strcmp(&name[strlen(name)-3],".gz")==0)) + { + fclose(fh); + char tempname[200]; + fprintf(stderr,"Trying to open zipped midi file...\n"); + if (uncompressFile(name,tempname)!=0) + { + fprintf(stderr,"ERROR: %s is not a (zipped) midi file\n",name); + ok=-2; + return NULL; + } + fh=fopen(tempname,"rb"); + fread(text,1,4,fh); + unlink(tempname); + } + + if (strncmp(text,"MThd",4)!=0) + { + fseek(fh,0,SEEK_SET); + long pos; + if (fsearch(fh,"MThd",&pos)==0) + { + fclose(fh); + fprintf(stderr,"ERROR: %s is not a midi file.\n",name); + ok=-2; + return NULL; + } + fseek(fh,pos,SEEK_SET); + fread(text,1,4,fh); + } + long header_size=readLong(fh); + info->format=readShort(fh); + info->ntracks=readShort(fh); + info->ticksPerCuarterNote=readShort(fh); + if (info->ticksPerCuarterNote<0) + { + fprintf(stderr,"ERROR: Ticks per cuarter note is negative !\n"); + fprintf(stderr,"Please report this error to : larrosa@kde.org\n"); + fclose(fh); + ok=-3; + return NULL; + } + if (header_size>6) fseek(fh,header_size-6,SEEK_CUR); + tracks=new MidiTrack*[info->ntracks]; + if (tracks==NULL) + { + fprintf(stderr,"ERROR: Not enough memory\n"); + fclose(fh); + ok=-4; + return NULL; + } + int i=0; + while (intracks) + { + fread(text,1,4,fh); + if (strncmp(text,"MTrk",4)!=0) + { + fprintf(stderr,"ERROR: Not a well built midi file\n"); + fprintf(stderr,"%s",text); + fclose(fh); + ok=-5; + return NULL; + } + tracks[i]=new MidiTrack(fh,info->ticksPerCuarterNote,i); + if (tracks[i]==NULL) + { + fprintf(stderr,"ERROR: Not enough memory"); + fclose(fh); + ok=-4; + return NULL; + } + i++; + } + + fclose(fh); + + return tracks; + +} + +void parseInfoData(MidiFileInfo *info,MidiTrack **tracks,float ratioTempo) +{ + + info->ticksTotal=0; + info->millisecsTotal=0.0; + info->ticksPlayed=0; + int i; + for (i=0;i<256;i++) + { + info->patchesUsed[i]=0; + } + + int parsing=1; + int trk,minTrk; + ulong tempo=(ulong)(500000 * ratioTempo); + +#ifdef MIDFILEDEBUG + printf("Parsing 1 ...\n"); +#endif + + int pgminchannel[16]; + for (i=0;i<16;i++) + { + pgminchannel[i]=0; + } + + int j; + for (i=0;intracks;i++) + { + tracks[i]->init(); + tracks[i]->changeTempo(tempo); + } + double prevms=0; + double minTime=0; + double maxTime; + MidiEvent *ev=new MidiEvent; + while (parsing) + { + prevms=minTime; + trk=0; + minTrk=0; + maxTime=minTime + 2 * 60000L; + minTime=maxTime; + while (trkntracks) + { + if (tracks[trk]->absMsOfNextEvent()absMsOfNextEvent(); + } + trk++; + } + if ((minTime==maxTime)) + { + parsing=0; +#ifdef MIDFILEDEBUG + printf("END of parsing\n"); +#endif + } + else + { + trk=0; + while (trkntracks) + { + tracks[trk]->currentMs(minTime); + trk++; + } + } + trk=minTrk; + tracks[trk]->readEvent(ev); + + switch (ev->command) + { + case (MIDI_NOTEON) : + if (ev->chn!=PERCUSSION_CHANNEL) + info->patchesUsed[pgminchannel[ev->chn]]++; + else + info->patchesUsed[ev->note+128]++; + break; + case (MIDI_PGM_CHANGE) : + pgminchannel[ev->chn]=(ev->patch); + break; + case (MIDI_SYSTEM_PREFIX) : + if (((ev->command|ev->chn)==META_EVENT)&&(ev->d1==ME_SET_TEMPO)) + { + tempo=(ulong)(((ev->data[0]<<16)|(ev->data[1]<<8)|(ev->data[2])) * ratioTempo); + for (j=0;jntracks;j++) + { + tracks[j]->changeTempo(tempo); + } + } + break; + } + } + + delete ev; + info->millisecsTotal=prevms; + + for (i=0;intracks;i++) + { + tracks[i]->init(); + } + +#ifdef MIDFILEDEBUG + printf("info.ticksTotal = %ld \n",info->ticksTotal); + printf("info.ticksPlayed= %ld \n",info->ticksPlayed); + printf("info.millisecsTotal = %g \n",info->millisecsTotal); + printf("info.TicksPerCN = %d \n",info->ticksPerCuarterNote); +#endif + +} + + +void parsePatchesUsed(MidiTrack **tracks,MidiFileInfo *info,int gm) +{ + int i; + for (i=0;i<256;i++) + { + info->patchesUsed[i]=0; + } + int parsing=1; + int trk,minTrk; + ulong tempo=500000; + +#ifdef MIDFILEDEBUG + printf("Parsing for patches ...\n"); +#endif + + int j; + for (i=0;intracks;i++) + { + tracks[i]->init(); + } + double prevms=0; + double minTime=0; + double maxTime; + ulong tmp; + MidiEvent *ev=new MidiEvent; + int pgminchannel[16]; + for (i=0;i<16;i++) + { + pgminchannel[i]=0; + } + + while (parsing) + { + prevms=minTime; + trk=0; + minTrk=0; + maxTime=minTime + 2 * 60000L; + minTime=maxTime; + while (trkntracks) + { + if (tracks[trk]->absMsOfNextEvent()absMsOfNextEvent(); + } + trk++; + } + if ((minTime==maxTime)) + { + parsing=0; +#ifdef MIDFILEDEBUG + printf("END of parsing for patches\n"); +#endif + } + else + { + trk=0; + while (trkntracks) + { + tracks[trk]->currentMs(minTime); + trk++; + } + } + trk=minTrk; + tracks[trk]->readEvent(ev); + switch (ev->command) + { + case (MIDI_NOTEON) : + if (ev->chn!=PERCUSSION_CHANNEL) + info->patchesUsed[pgminchannel[ev->chn]]++; + else + info->patchesUsed[ev->note+128]++; + break; + case (MIDI_PGM_CHANGE) : + pgminchannel[ev->chn]=(gm==1)?(ev->patch):(MT32toGM[ev->patch]); + break; + case (MIDI_SYSTEM_PREFIX) : + if (((ev->command|ev->chn)==META_EVENT)&&(ev->d1==ME_SET_TEMPO)) + { + if (tempoToMetronomeTempo(tmp=((ev->data[0]<<16)|(ev->data[1]<<8)|(ev->data[2])))>=8) + { + tempo=tmp; + // printf("setTempo %ld\n",tempo); + for (j=0;jntracks;j++) + { + tracks[j]->changeTempo(tempo); + } + } + } + break; + } + } + + delete ev; + + for (i=0;intracks;i++) + { + tracks[i]->init(); + } + +} + +int fsearch(FILE *fh,const char *text,long *ptr) + // Search for "text" through the fh file and then returns : + // text MUST BE smaller than 256 characters + // 0 if not was found + // 1 if it was found and in ptr (if !=NULL) the position where text begins. +{ + if ((text==NULL)||(text[0]==0)) return 0; + char buf[1024]; + char tmp[256]; + long pos; + int l=strlen(text); + int i,k,r; + while (!feof(fh)) + { + pos=ftell(fh); + k=fread(buf,1,1024,fh); + i=0; + while (i=l) + r=strncmp(text,&buf[i],l); + else + { + fseek(fh,pos+i,SEEK_SET); + if (fread(tmp,1,l,fh)<(uint)l) return 0; + fseek(fh,pos+k,SEEK_SET); + r=strncmp(text,tmp,l); + } + if (r==0) + { + if (ptr!=NULL) *ptr=pos+i; + return 1; + } + } + i++; + } + } + return 0; +} diff --git a/libtdemid/midimapper.cc b/libtdemid/midimapper.cc deleted file mode 100644 index 837728410..000000000 --- a/libtdemid/midimapper.cc +++ /dev/null @@ -1,456 +0,0 @@ -/************************************************************************** - - 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/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 - -***************************************************************************/ -#include "midimapper.h" -#include -#include -#include -#ifdef HAVE_CONFIG_H -#include -#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)&&(iname, 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) - { - 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) - { - 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; -} diff --git a/libtdemid/midimapper.cpp b/libtdemid/midimapper.cpp new file mode 100644 index 000000000..157ef864f --- /dev/null +++ b/libtdemid/midimapper.cpp @@ -0,0 +1,456 @@ +/************************************************************************** + + 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 + +***************************************************************************/ +#include "midimapper.h" +#include +#include +#include +#ifdef HAVE_CONFIG_H +#include +#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)&&(iname, 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) + { + 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) + { + 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; +} diff --git a/libtdemid/midiout.cc b/libtdemid/midiout.cc deleted file mode 100644 index 24a209cce..000000000 --- a/libtdemid/midiout.cc +++ /dev/null @@ -1,301 +0,0 @@ -/************************************************************************** - - midiout.cc - class midiOut which handles external midi devices - 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 - -***************************************************************************/ -#include "midiout.h" -#include -#include -#include -#include "sndcard.h" -#include -#include -#include -#include -#include "midispec.h" -#include "alsaout.h" - -#ifdef HAVE_CONFIG_H -#include -#endif - -#include - -SEQ_USE_EXTBUF(); - -MidiOut::MidiOut(int d) -{ - seqfd = -1; - devicetype=KMID_EXTERNAL_MIDI; - device= d; - volumepercentage=100; - map=new MidiMapper(NULL); - if (map==NULL) { printfdebug("ERROR : midiOut : Map is NULL\n"); return; }; - _ok=1; -} - -MidiOut::~MidiOut() -{ - delete map; - closeDev(); -} - -void MidiOut::openDev (int sqfd) -{ -#ifdef HAVE_OSS_SUPPORT - _ok=1; - seqfd=sqfd; - if (seqfd==-1) - { - printfdebug("ERROR: Could not open /dev/sequencer\n"); - _ok=0; - return; - } -#endif -} - -void MidiOut::closeDev (void) -{ - if (!ok()) return; -// if (deviceType()!=KMID_ALSA) allNotesOff(); - SEQ_STOP_TIMER(); - SEQ_DUMPBUF(); - seqfd=-1; -} - -void MidiOut::initDev (void) -{ -#ifdef HAVE_OSS_SUPPORT - int chn; - if (!ok()) return; - uchar gm_reset[5]={0x7e, 0x7f, 0x09, 0x01, 0xf7}; - sysex(gm_reset, sizeof(gm_reset)); - for (chn=0;chn<16;chn++) - { - chnmute[chn]=0; - chnPatchChange(chn,0); - chnPressure(chn,127); - chnPitchBender(chn, 0x00, 0x40); - chnController(chn, CTL_MAIN_VOLUME,110*volumepercentage); - chnController(chn, CTL_EXT_EFF_DEPTH, 0); - chnController(chn, CTL_CHORUS_DEPTH, 0); - chnController(chn, 0x4a, 127); - } -#endif -} - -void MidiOut::setMidiMapper(MidiMapper *_map) -{ - delete map; - map=_map; -} - -void MidiOut::noteOn (uchar chn, uchar note, uchar vel) -{ - if (vel==0) - { - noteOff(chn,note,vel); - } - else - { - SEQ_MIDIOUT(device, MIDI_NOTEON + map->channel(chn)); - SEQ_MIDIOUT(device, map->key(chn,chnpatch[chn],note)); - SEQ_MIDIOUT(device, vel); - } -#ifdef MIDIOUTDEBUG - printfdebug("Note ON >\t chn : %d\tnote : %d\tvel: %d\n",chn,note,vel); -#endif -} - -void MidiOut::noteOff (uchar chn, uchar note, uchar vel) -{ - SEQ_MIDIOUT(device, MIDI_NOTEOFF + map->channel(chn)); - SEQ_MIDIOUT(device, map->key(chn,chnpatch[chn],note)); - SEQ_MIDIOUT(device, vel); -#ifdef MIDIOUTDEBUG - printfdebug("Note OFF >\t chn : %d\tnote : %d\tvel: %d\n",chn,note,vel); -#endif -} - -void MidiOut::keyPressure (uchar chn, uchar note, uchar vel) -{ - SEQ_MIDIOUT(device, MIDI_KEY_PRESSURE + map->channel(chn)); - SEQ_MIDIOUT(device, map->key(chn,chnpatch[chn],note)); - SEQ_MIDIOUT(device, vel); -} - -void MidiOut::chnPatchChange (uchar chn, uchar patch) -{ -#ifdef MIDIOUTDEBUG - printfdebug("PATCHCHANGE [%d->%d] %d -> %d\n", - chn,map->channel(chn),patch,map->patch(chn,patch)); -#endif - SEQ_MIDIOUT(device, MIDI_PGM_CHANGE + map->channel(chn)); - SEQ_MIDIOUT(device, map->patch(chn,patch)); - chnpatch[chn]=patch; -} - -void MidiOut::chnPressure (uchar chn, uchar vel) -{ - SEQ_MIDIOUT(device, MIDI_CHN_PRESSURE + map->channel(chn)); - SEQ_MIDIOUT(device, vel); - - chnpressure[chn]=vel; -} - -void MidiOut::chnPitchBender(uchar chn,uchar lsb, uchar msb) -{ - SEQ_MIDIOUT(device, MIDI_PITCH_BEND + map->channel(chn)); - /* -#ifdef AT_HOME - short pbs=((short)msb<<7) | (lsb & 0x7F); - pbs=pbs-0x2000; - short pbs2=(((long)pbs*672)/4096); - printfdebug("Pitch Bender (%d): %d -> %d \n",chn,pbs,pbs2); - pbs2=pbs2+0x2000; - lsb=pbs2 & 0x7F; - msb=(pbs2 >> 7)&0x7F; -#endif - */ - map->pitchBender(chn,lsb,msb); - SEQ_MIDIOUT(device, lsb); - SEQ_MIDIOUT(device, msb); - chnbender[chn]=(msb << 8) | (lsb & 0xFF); -} - -void MidiOut::chnController (uchar chn, uchar ctl, uchar v) -{ - SEQ_MIDIOUT(device, MIDI_CTL_CHANGE + map->channel(chn)); -#ifdef AT_HOME - if (ctl==11) ctl=7; -#endif - map->controller(chn,ctl,v); - if ((ctl==11)||(ctl==7)) - { - v=(v*volumepercentage)/100; - if (v>127) v=127; - } - - SEQ_MIDIOUT(device, ctl); - SEQ_MIDIOUT(device, v); - - chncontroller[chn][ctl]=v; -} - -void MidiOut::sysex(uchar *data, ulong size) -{ - ulong i=0; - SEQ_MIDIOUT(device, MIDI_SYSTEM_PREFIX); - while (ifilename() : ""; -} - -const char * MidiOut::deviceName(void) const -{ - switch (deviceType()) - { - case (KMID_EXTERNAL_MIDI) : return "External Midi"; - case (KMID_SYNTH) : return "Synth"; - case (KMID_FM) : return "FM"; - case (KMID_GUS) : return "GUS"; - case (KMID_AWE) : return "AWE"; - case (KMID_ALSA) : return reinterpret_cast(this)->deviceName(); - } - return "Unknown"; -} - -void MidiOut::sync(int i) -{ - if (deviceType()==KMID_ALSA) { // XXX : sync should be virtual after next bic - reinterpret_cast(this)->sync(i); - return; - } - SEQ_DUMPBUF(); -} diff --git a/libtdemid/midiout.cpp b/libtdemid/midiout.cpp new file mode 100644 index 000000000..c4949b03c --- /dev/null +++ b/libtdemid/midiout.cpp @@ -0,0 +1,301 @@ +/************************************************************************** + + midiout.cpp - class midiOut which handles external midi devices + 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 + +***************************************************************************/ +#include "midiout.h" +#include +#include +#include +#include "sndcard.h" +#include +#include +#include +#include +#include "midispec.h" +#include "alsaout.h" + +#ifdef HAVE_CONFIG_H +#include +#endif + +#include + +SEQ_USE_EXTBUF(); + +MidiOut::MidiOut(int d) +{ + seqfd = -1; + devicetype=KMID_EXTERNAL_MIDI; + device= d; + volumepercentage=100; + map=new MidiMapper(NULL); + if (map==NULL) { printfdebug("ERROR : midiOut : Map is NULL\n"); return; }; + _ok=1; +} + +MidiOut::~MidiOut() +{ + delete map; + closeDev(); +} + +void MidiOut::openDev (int sqfd) +{ +#ifdef HAVE_OSS_SUPPORT + _ok=1; + seqfd=sqfd; + if (seqfd==-1) + { + printfdebug("ERROR: Could not open /dev/sequencer\n"); + _ok=0; + return; + } +#endif +} + +void MidiOut::closeDev (void) +{ + if (!ok()) return; +// if (deviceType()!=KMID_ALSA) allNotesOff(); + SEQ_STOP_TIMER(); + SEQ_DUMPBUF(); + seqfd=-1; +} + +void MidiOut::initDev (void) +{ +#ifdef HAVE_OSS_SUPPORT + int chn; + if (!ok()) return; + uchar gm_reset[5]={0x7e, 0x7f, 0x09, 0x01, 0xf7}; + sysex(gm_reset, sizeof(gm_reset)); + for (chn=0;chn<16;chn++) + { + chnmute[chn]=0; + chnPatchChange(chn,0); + chnPressure(chn,127); + chnPitchBender(chn, 0x00, 0x40); + chnController(chn, CTL_MAIN_VOLUME,110*volumepercentage); + chnController(chn, CTL_EXT_EFF_DEPTH, 0); + chnController(chn, CTL_CHORUS_DEPTH, 0); + chnController(chn, 0x4a, 127); + } +#endif +} + +void MidiOut::setMidiMapper(MidiMapper *_map) +{ + delete map; + map=_map; +} + +void MidiOut::noteOn (uchar chn, uchar note, uchar vel) +{ + if (vel==0) + { + noteOff(chn,note,vel); + } + else + { + SEQ_MIDIOUT(device, MIDI_NOTEON + map->channel(chn)); + SEQ_MIDIOUT(device, map->key(chn,chnpatch[chn],note)); + SEQ_MIDIOUT(device, vel); + } +#ifdef MIDIOUTDEBUG + printfdebug("Note ON >\t chn : %d\tnote : %d\tvel: %d\n",chn,note,vel); +#endif +} + +void MidiOut::noteOff (uchar chn, uchar note, uchar vel) +{ + SEQ_MIDIOUT(device, MIDI_NOTEOFF + map->channel(chn)); + SEQ_MIDIOUT(device, map->key(chn,chnpatch[chn],note)); + SEQ_MIDIOUT(device, vel); +#ifdef MIDIOUTDEBUG + printfdebug("Note OFF >\t chn : %d\tnote : %d\tvel: %d\n",chn,note,vel); +#endif +} + +void MidiOut::keyPressure (uchar chn, uchar note, uchar vel) +{ + SEQ_MIDIOUT(device, MIDI_KEY_PRESSURE + map->channel(chn)); + SEQ_MIDIOUT(device, map->key(chn,chnpatch[chn],note)); + SEQ_MIDIOUT(device, vel); +} + +void MidiOut::chnPatchChange (uchar chn, uchar patch) +{ +#ifdef MIDIOUTDEBUG + printfdebug("PATCHCHANGE [%d->%d] %d -> %d\n", + chn,map->channel(chn),patch,map->patch(chn,patch)); +#endif + SEQ_MIDIOUT(device, MIDI_PGM_CHANGE + map->channel(chn)); + SEQ_MIDIOUT(device, map->patch(chn,patch)); + chnpatch[chn]=patch; +} + +void MidiOut::chnPressure (uchar chn, uchar vel) +{ + SEQ_MIDIOUT(device, MIDI_CHN_PRESSURE + map->channel(chn)); + SEQ_MIDIOUT(device, vel); + + chnpressure[chn]=vel; +} + +void MidiOut::chnPitchBender(uchar chn,uchar lsb, uchar msb) +{ + SEQ_MIDIOUT(device, MIDI_PITCH_BEND + map->channel(chn)); + /* +#ifdef AT_HOME + short pbs=((short)msb<<7) | (lsb & 0x7F); + pbs=pbs-0x2000; + short pbs2=(((long)pbs*672)/4096); + printfdebug("Pitch Bender (%d): %d -> %d \n",chn,pbs,pbs2); + pbs2=pbs2+0x2000; + lsb=pbs2 & 0x7F; + msb=(pbs2 >> 7)&0x7F; +#endif + */ + map->pitchBender(chn,lsb,msb); + SEQ_MIDIOUT(device, lsb); + SEQ_MIDIOUT(device, msb); + chnbender[chn]=(msb << 8) | (lsb & 0xFF); +} + +void MidiOut::chnController (uchar chn, uchar ctl, uchar v) +{ + SEQ_MIDIOUT(device, MIDI_CTL_CHANGE + map->channel(chn)); +#ifdef AT_HOME + if (ctl==11) ctl=7; +#endif + map->controller(chn,ctl,v); + if ((ctl==11)||(ctl==7)) + { + v=(v*volumepercentage)/100; + if (v>127) v=127; + } + + SEQ_MIDIOUT(device, ctl); + SEQ_MIDIOUT(device, v); + + chncontroller[chn][ctl]=v; +} + +void MidiOut::sysex(uchar *data, ulong size) +{ + ulong i=0; + SEQ_MIDIOUT(device, MIDI_SYSTEM_PREFIX); + while (ifilename() : ""; +} + +const char * MidiOut::deviceName(void) const +{ + switch (deviceType()) + { + case (KMID_EXTERNAL_MIDI) : return "External Midi"; + case (KMID_SYNTH) : return "Synth"; + case (KMID_FM) : return "FM"; + case (KMID_GUS) : return "GUS"; + case (KMID_AWE) : return "AWE"; + case (KMID_ALSA) : return reinterpret_cast(this)->deviceName(); + } + return "Unknown"; +} + +void MidiOut::sync(int i) +{ + if (deviceType()==KMID_ALSA) { // XXX : sync should be virtual after next bic + reinterpret_cast(this)->sync(i); + return; + } + SEQ_DUMPBUF(); +} diff --git a/libtdemid/midistat.cc b/libtdemid/midistat.cc deleted file mode 100644 index 6a6c94b0c..000000000 --- a/libtdemid/midistat.cc +++ /dev/null @@ -1,115 +0,0 @@ -/************************************************************************** - - midistat.cc - class MidiStatus, change it internally and then send it. - 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 - -***************************************************************************/ -#include "midistat.h" -#include "deviceman.h" -#include "sndcard.h" - -#ifdef HAVE_CONFIG_H -#include -#endif - -extern int MT32toGM[128]; - -MidiStatus::MidiStatus() -{ - int i; - tempo=1000000; - for (int chn=0;chn<16;chn++) - { - chn_patch[chn]=0; - chn_bender[chn]=0x4000; - chn_pressure[chn]=127; - for (i=0;i<256;i++) - chn_controller[chn][i]=0; - chn_controller[chn][CTL_MAIN_VOLUME]=127; - chn_controller[chn][11]=127; - chn_controller[chn][0x4a]=127; - chn_lastisvolumeev[chn]=1; - } -} - -MidiStatus::~MidiStatus() -{ -} - -// void noteOn ( uchar chn, uchar note, uchar vel ); -// void noteOff ( uchar chn, uchar note, uchar vel ); - -void MidiStatus::chnPatchChange ( uchar chn, uchar patch ) -{ - chn_patch[chn]=patch; -} - -void MidiStatus::chnPressure ( uchar chn, uchar vel ) -{ - chn_pressure[chn]=vel; -} - -void MidiStatus::chnPitchBender ( uchar chn, uchar lsb, uchar msb ) -{ - chn_bender[chn]=((int)msb<<8|lsb); -} - -void MidiStatus::chnController ( uchar chn, uchar ctl , uchar v ) -{ - if (ctl==7) chn_lastisvolumeev[chn]=1; - else if (ctl==11) chn_lastisvolumeev[chn]=0; - - chn_controller[chn][ctl]=v; -} - -void MidiStatus::tmrSetTempo(int v) -{ - tempo=v; -} - -void MidiStatus::sendData(DeviceManager *midi,int gm) -{ - for (int chn=0;chn<16;chn++) - { -#ifdef MIDISTATDEBUG - printf("Restoring channel %d\n",chn); -#endif - midi->chnPatchChange(chn, - (gm==1)?(chn_patch[chn]):(MT32toGM[chn_patch[chn]])); - midi->chnPitchBender(chn,chn_bender[chn]&0xFF,chn_bender[chn]>>8); - midi->chnPressure(chn,chn_pressure[chn]); - if (chn_lastisvolumeev[chn]) - { - midi->chnController(chn,11,chn_controller[chn][11]); - midi->chnController(chn,CTL_MAIN_VOLUME,chn_controller[chn][CTL_MAIN_VOLUME]); - } else { - midi->chnController(chn,CTL_MAIN_VOLUME,chn_controller[chn][CTL_MAIN_VOLUME]); - midi->chnController(chn,11,chn_controller[chn][11]); - } - /* - for (int i=0;i<256;i++) - midi->chnController(chn,i,chn_controller[chn][i]); - */ - } - midi->tmrSetTempo(tempo); - midi->sync(); -} diff --git a/libtdemid/midistat.cpp b/libtdemid/midistat.cpp new file mode 100644 index 000000000..7bd02c95a --- /dev/null +++ b/libtdemid/midistat.cpp @@ -0,0 +1,115 @@ +/************************************************************************** + + midistat.cpp - class MidiStatus, change it internally and then send it. + 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 + +***************************************************************************/ +#include "midistat.h" +#include "deviceman.h" +#include "sndcard.h" + +#ifdef HAVE_CONFIG_H +#include +#endif + +extern int MT32toGM[128]; + +MidiStatus::MidiStatus() +{ + int i; + tempo=1000000; + for (int chn=0;chn<16;chn++) + { + chn_patch[chn]=0; + chn_bender[chn]=0x4000; + chn_pressure[chn]=127; + for (i=0;i<256;i++) + chn_controller[chn][i]=0; + chn_controller[chn][CTL_MAIN_VOLUME]=127; + chn_controller[chn][11]=127; + chn_controller[chn][0x4a]=127; + chn_lastisvolumeev[chn]=1; + } +} + +MidiStatus::~MidiStatus() +{ +} + +// void noteOn ( uchar chn, uchar note, uchar vel ); +// void noteOff ( uchar chn, uchar note, uchar vel ); + +void MidiStatus::chnPatchChange ( uchar chn, uchar patch ) +{ + chn_patch[chn]=patch; +} + +void MidiStatus::chnPressure ( uchar chn, uchar vel ) +{ + chn_pressure[chn]=vel; +} + +void MidiStatus::chnPitchBender ( uchar chn, uchar lsb, uchar msb ) +{ + chn_bender[chn]=((int)msb<<8|lsb); +} + +void MidiStatus::chnController ( uchar chn, uchar ctl , uchar v ) +{ + if (ctl==7) chn_lastisvolumeev[chn]=1; + else if (ctl==11) chn_lastisvolumeev[chn]=0; + + chn_controller[chn][ctl]=v; +} + +void MidiStatus::tmrSetTempo(int v) +{ + tempo=v; +} + +void MidiStatus::sendData(DeviceManager *midi,int gm) +{ + for (int chn=0;chn<16;chn++) + { +#ifdef MIDISTATDEBUG + printf("Restoring channel %d\n",chn); +#endif + midi->chnPatchChange(chn, + (gm==1)?(chn_patch[chn]):(MT32toGM[chn_patch[chn]])); + midi->chnPitchBender(chn,chn_bender[chn]&0xFF,chn_bender[chn]>>8); + midi->chnPressure(chn,chn_pressure[chn]); + if (chn_lastisvolumeev[chn]) + { + midi->chnController(chn,11,chn_controller[chn][11]); + midi->chnController(chn,CTL_MAIN_VOLUME,chn_controller[chn][CTL_MAIN_VOLUME]); + } else { + midi->chnController(chn,CTL_MAIN_VOLUME,chn_controller[chn][CTL_MAIN_VOLUME]); + midi->chnController(chn,11,chn_controller[chn][11]); + } + /* + for (int i=0;i<256;i++) + midi->chnController(chn,i,chn_controller[chn][i]); + */ + } + midi->tmrSetTempo(tempo); + midi->sync(); +} diff --git a/libtdemid/mt32togm.cc b/libtdemid/mt32togm.cc deleted file mode 100644 index a59eb959c..000000000 --- a/libtdemid/mt32togm.cc +++ /dev/null @@ -1,18 +0,0 @@ -#include "mt32togm.h" - -int MT32toGM[128] = -{ - 0, 1, 2, 4, 4, 5, 5, 3, 16, 16, - 16, 16, 19, 19, 19, 21, 6, 6, 6, 7, - 7, 7, 8, 8, 62, 57, 63, 58, 38, 38, - 39, 39, 88, 33, 52, 35, 97, 100, 38, 39, - 14, 102, 68, 103, 44, 92, 46, 80, 48, 49, - 51, 45, 40, 40, 42, 42, 43, 46, 46, 24, - 25, 28, 27, 104, 32, 32, 34, 33, 36, 37, - 39, 35, 79, 73, 76, 72, 74, 75, 64, 65, - 66, 67, 71, 71, 69, 70, 60, 22, 56, 59, - 57, 63, 60, 60, 58, 61, 61, 11, 11, 99, - 100, 9, 14, 13, 12, 107, 106, 77, 78, 78, - 76, 111, 47, 117, 127, 115, 118, 116, 118, 126, - 121, 121, 55, 124, 120, 125, 126, 127 -}; diff --git a/libtdemid/mt32togm.cpp b/libtdemid/mt32togm.cpp new file mode 100644 index 000000000..a59eb959c --- /dev/null +++ b/libtdemid/mt32togm.cpp @@ -0,0 +1,18 @@ +#include "mt32togm.h" + +int MT32toGM[128] = +{ + 0, 1, 2, 4, 4, 5, 5, 3, 16, 16, + 16, 16, 19, 19, 19, 21, 6, 6, 6, 7, + 7, 7, 8, 8, 62, 57, 63, 58, 38, 38, + 39, 39, 88, 33, 52, 35, 97, 100, 38, 39, + 14, 102, 68, 103, 44, 92, 46, 80, 48, 49, + 51, 45, 40, 40, 42, 42, 43, 46, 46, 24, + 25, 28, 27, 104, 32, 32, 34, 33, 36, 37, + 39, 35, 79, 73, 76, 72, 74, 75, 64, 65, + 66, 67, 71, 71, 69, 70, 60, 22, 56, 59, + 57, 63, 60, 60, 58, 61, 61, 11, 11, 99, + 100, 9, 14, 13, 12, 107, 106, 77, 78, 78, + 76, 111, 47, 117, 127, 115, 118, 116, 118, 126, + 121, 121, 55, 124, 120, 125, 126, 127 +}; diff --git a/libtdemid/notearray.cc b/libtdemid/notearray.cc deleted file mode 100644 index 9899fd837..000000000 --- a/libtdemid/notearray.cc +++ /dev/null @@ -1,122 +0,0 @@ -/************************************************************************** - - notearray.cc - NoteArray class, which holds an array of notes - This file is part of LibKMid 0.9.5 - Copyright (C) 1998,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 - -***************************************************************************/ - -#include "notearray.h" -#include - -NoteArray::NoteArray(void) -{ - totalAllocated=50; - data=new noteCmd[totalAllocated]; - lastAdded=0L; -} - -NoteArray::~NoteArray() -{ - delete data; - totalAllocated=0; -} - -NoteArray::noteCmd *NoteArray::pointerTo(ulong pos) -{ - if (pos=totalAllocated) - { - noteCmd *tmp=new noteCmd[totalAllocated*2]; - memcpy(tmp,data,sizeof(noteCmd)*totalAllocated); - delete data; - data=tmp; - totalAllocated*=2; - } - return &data[pos]; -} - -void NoteArray::at(ulong pos, ulong ms,int chn,int cmd,int note) -{ - noteCmd *tmp=pointerTo(pos); - tmp->ms=ms; - tmp->chn=chn; - tmp->cmd=cmd; - tmp->note=note; -} - -void NoteArray::at(ulong pos, noteCmd s) -{ - noteCmd *tmp=pointerTo(pos); - tmp->ms=s.ms; - tmp->chn=s.chn; - tmp->cmd=s.cmd; - tmp->note=s.note; -} - -NoteArray::noteCmd NoteArray::at(int pos) -{ - return *pointerTo(pos); -} - -void NoteArray::add(ulong ms,int chn,int cmd,int note) -{ - if (lastAdded==NULL) - { - lastAdded=data; - last=0; - } - else - { - last++; - if (last==totalAllocated) lastAdded=pointerTo(totalAllocated); - else lastAdded++; - } - lastAdded->ms=ms; - lastAdded->chn=chn; - lastAdded->cmd=cmd; - lastAdded->note=note; -} - -void NoteArray::next(void) -{ - if (it==lastAdded) {it=NULL;return;}; - it++; -} - -void NoteArray::moveIteratorTo(ulong ms,int *pgm) -{ - noteCmd *ncmd; - iteratorBegin(); - ncmd=get(); - int pgm2[16]; - for (int j=0;j<16;j++) pgm2[j]=0; - while ((ncmd!=NULL)&&(ncmd->mscmd==2) pgm2[ncmd->chn]=ncmd->note; - next(); - ncmd=get(); - } - if (pgm!=NULL) - { - for (int i=0;i<16;i++) pgm[i]=pgm2[i]; - } -} diff --git a/libtdemid/notearray.cpp b/libtdemid/notearray.cpp new file mode 100644 index 000000000..d08a5b074 --- /dev/null +++ b/libtdemid/notearray.cpp @@ -0,0 +1,122 @@ +/************************************************************************** + + notearray.cpp - NoteArray class, which holds an array of notes + This file is part of LibKMid 0.9.5 + Copyright (C) 1998,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 + +***************************************************************************/ + +#include "notearray.h" +#include + +NoteArray::NoteArray(void) +{ + totalAllocated=50; + data=new noteCmd[totalAllocated]; + lastAdded=0L; +} + +NoteArray::~NoteArray() +{ + delete data; + totalAllocated=0; +} + +NoteArray::noteCmd *NoteArray::pointerTo(ulong pos) +{ + if (pos=totalAllocated) + { + noteCmd *tmp=new noteCmd[totalAllocated*2]; + memcpy(tmp,data,sizeof(noteCmd)*totalAllocated); + delete data; + data=tmp; + totalAllocated*=2; + } + return &data[pos]; +} + +void NoteArray::at(ulong pos, ulong ms,int chn,int cmd,int note) +{ + noteCmd *tmp=pointerTo(pos); + tmp->ms=ms; + tmp->chn=chn; + tmp->cmd=cmd; + tmp->note=note; +} + +void NoteArray::at(ulong pos, noteCmd s) +{ + noteCmd *tmp=pointerTo(pos); + tmp->ms=s.ms; + tmp->chn=s.chn; + tmp->cmd=s.cmd; + tmp->note=s.note; +} + +NoteArray::noteCmd NoteArray::at(int pos) +{ + return *pointerTo(pos); +} + +void NoteArray::add(ulong ms,int chn,int cmd,int note) +{ + if (lastAdded==NULL) + { + lastAdded=data; + last=0; + } + else + { + last++; + if (last==totalAllocated) lastAdded=pointerTo(totalAllocated); + else lastAdded++; + } + lastAdded->ms=ms; + lastAdded->chn=chn; + lastAdded->cmd=cmd; + lastAdded->note=note; +} + +void NoteArray::next(void) +{ + if (it==lastAdded) {it=NULL;return;}; + it++; +} + +void NoteArray::moveIteratorTo(ulong ms,int *pgm) +{ + noteCmd *ncmd; + iteratorBegin(); + ncmd=get(); + int pgm2[16]; + for (int j=0;j<16;j++) pgm2[j]=0; + while ((ncmd!=NULL)&&(ncmd->mscmd==2) pgm2[ncmd->chn]=ncmd->note; + next(); + ncmd=get(); + } + if (pgm!=NULL) + { + for (int i=0;i<16;i++) pgm[i]=pgm2[i]; + } +} diff --git a/libtdemid/player.cc b/libtdemid/player.cc deleted file mode 100644 index ff7093496..000000000 --- a/libtdemid/player.cc +++ /dev/null @@ -1,959 +0,0 @@ -/************************************************************************** - - player.cc - class MidiPlayer. Plays a set of tracks - 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 "player.h" -#include "sndcard.h" -#include "midispec.h" -#include -#include -#include -#include "midistat.h" -#include "mt32togm.h" - -//#define PLAYERDEBUG -//#define GENERAL_DEBUG_MESSAGES - -#define T2MS(ticks) (((double)ticks)*(double)60000L)/((double)tempoToMetronomeTempo(tempo)*(double)info->ticksPerCuarterNote) - -#define MS2T(ms) (((ms)*(double)tempoToMetronomeTempo(tempo)*(double)info->ticksPerCuarterNote)/((double)60000L)) - -#define REMOVEDUPSTRINGS - -MidiPlayer::MidiPlayer(DeviceManager *midi_,PlayerController *pctl) -{ - midi=midi_; - info=NULL; - tracks=NULL; - songLoaded=0; - ctl=pctl; - spev=NULL; - na=NULL; - parsesong=true; - generatebeats=false; -} - -MidiPlayer::~MidiPlayer() -{ - removeSpecialEvents(); - removeSong(); -} - -void MidiPlayer::removeSong(void) -{ - if ((songLoaded)&&(tracks!=NULL)) - { -#ifdef PLAYERDEBUG - printf("Removing song from memory\n"); -#endif - int i=0; - while (intracks) - { - if (tracks[i]!=NULL) delete tracks[i]; - i++; - } - delete tracks; - tracks=NULL; - if (info!=NULL) - { - delete info; - info=NULL; - } - } - songLoaded=0; -} - -int MidiPlayer::loadSong(const char *filename) -{ - removeSong(); -#ifdef PLAYERDEBUG - printf("Loading Song : %s\n",filename); -#endif - info=new MidiFileInfo; - int ok; - tracks=readMidiFile(filename,info,ok); - if (ok<0) return ok; - if (tracks==NULL) return -4; - - parseInfoData(info,tracks,ctl->ratioTempo); - - if (parsesong) - { - parseSpecialEvents(); - if (generatebeats) generateBeats(); - } - - songLoaded=1; - return 0; -} - -void MidiPlayer::insertBeat(SpecialEvent *ev,ulong ms,int num,int den) -{ - SpecialEvent *beat=new SpecialEvent; - beat->next=ev->next; - ev->next=beat; - beat->id=1; - beat->type=7; - beat->absmilliseconds=ms; - beat->num=num; - beat->den=den; -} - - -void MidiPlayer::generateBeats(void) -{ -#ifdef PLAYERDEBUG - printf("player::Generating Beats...\n"); -#endif - - if (spev==NULL) return; - SpecialEvent *ev=spev; - SpecialEvent *nextev=ev->next; - ulong tempo=(ulong)(500000 * ctl->ratioTempo); - int i=1; - int num=4; - int den=4; - // ulong beatstep=((double)tempo*4/(den*1000)); - // ulong beatstep=T2MS(info->ticksPerCuarterNote*(4/den)); - double ticksleft=(((double)info->ticksPerCuarterNote*4)/den); - - double beatstep=T2MS(ticksleft); - double nextbeatms=0; - double lastbeatms=0; - double measurems=0; - - while (nextev!=NULL) - { - switch (ev->type) - { - case (0): // End of list - { - };break; - case (1): // Text - case (2): // Lyrics - { - };break; - case (3): // Change Tempo - { - lastbeatms=ev->absmilliseconds; - ticksleft=MS2T(nextbeatms-lastbeatms); - tempo=ev->tempo; - nextbeatms=lastbeatms+T2MS(ticksleft); - // printf("Change at %lu to %d\n",ev->absmilliseconds,ev->tempo); - // beatstep=((double)tempo*4/(den*1000)); - beatstep=T2MS(((static_cast(info->ticksPerCuarterNote)*4)/den)); - };break; - case (6): // Change number of beats per measure - { - num=ev->num; - i=1; - den=ev->den; - // printf("Change at %lu to %d/%d\n",ev->absmilliseconds,num,den); - // beatstep=((double)tempo*4/(den*1000)); - // beatstep=T2MS(info->ticksPerCuarterNote*(4/den)); - beatstep=T2MS((((double)info->ticksPerCuarterNote*4)/den)); - nextbeatms=ev->absmilliseconds; - };break; - }; - if (nextev->absmilliseconds>nextbeatms) - { - //printf("Adding %d,%d\n",num,tot); - //printf("beat at %g , %d/%d\n",nextbeatms,i,num); - //printf(" %ld %d\n",nextev->absmilliseconds,nextev->type); - if (i == 1) { - measurems=nextbeatms; - } - insertBeat(ev, static_cast(nextbeatms), i++, num); - if (i > num) { - i=1; - } - lastbeatms=nextbeatms; - nextbeatms+=beatstep; - // nextbeatms=measurems+beatstep*i; - - ticksleft = ( (static_cast(info->ticksPerCuarterNote)*4) / den); - - } - - ev=ev->next; - nextev=ev->next; - } - - /* ev==NULL doesn't indicate the end of the song, so continue generating beats */ - - if (ev!=NULL) - { - if (ev->type==0) - { - ev=spev; - /* Looking if ev->next is NULL is not needed because - we are sure that a ev->type == 0 exists, we just have - to assure that the first spev is not the only one */ - if (ev->next!=NULL) - while (ev->next->type!=0) ev=ev->next; - } - while (nextbeatmsmillisecsTotal) - { - // printf("beat2 at %g , %d/%d\n",nextbeatms,i,num); - if (i==1) measurems=nextbeatms; - insertBeat(ev, static_cast(nextbeatms), i++, num); - if (i>num) i=1; - nextbeatms+=beatstep; - ev=ev->next; - } - } - - /* Regenerate IDs */ - - ev=spev; - i=1; - while (ev!=NULL) - { - ev->id=i++; - ev=ev->next; - } - - -#ifdef PLAYERDEBUG - printf("player::Beats Generated\n"); -#endif - -} - -void MidiPlayer::removeSpecialEvents(void) -{ - SpecialEvent * ev=spev; - while (spev!=NULL) - { - ev=spev->next; - delete spev; - spev=ev; - } - delete na; - na=0; -} - -void MidiPlayer::parseSpecialEvents(void) -{ -#ifdef PLAYERDEBUG - printf("player::Parsing...\n"); -#endif - removeSpecialEvents(); - spev=new SpecialEvent; - if (spev==NULL) return; - SpecialEvent *pspev=spev; - pspev->type=0; - pspev->ticks=0; - if (na) delete na; - na=new NoteArray(); - if (!na) { delete spev; spev=0L; return; }; - int trk; - int minTrk; - double minTime=0; - double maxTime; - ulong tempo=(ulong)(500000 * (ctl->ratioTempo)); - ulong firsttempo=0; - for (int i=0;intracks;i++) - { - tracks[i]->init(); - tracks[i]->changeTempo(tempo); - } - MidiEvent *ev=new MidiEvent; - //ulong mspass; - double prevms=0; - int spev_id=1; - int j; - int parsing=1; -#ifdef REMOVEDUPSTRINGS - char lasttext[1024]; - ulong lasttexttime=0; - lasttext[0]=0; - int lasttexttype=0; -#endif - while (parsing) - { - prevms=minTime; - trk=0; - minTrk=0; - maxTime=minTime + 2 * 60000L; - minTime=maxTime; - parsing=0; - while (trkntracks) - { - if (tracks[trk]->absMsOfNextEvent()absMsOfNextEvent(); - parsing=1; - } - trk++; - } - // if ((minTime==maxTime)) - if (parsing==0) - { - // parsing=0; -#ifdef PLAYERDEBUG - printf("END of parsing\n"); -#endif - } - else - { - // mspass=(ulong)(minTime-prevms); - trk=0; - while (trkntracks) - { - tracks[trk]->currentMs(minTime); - trk++; - } - } - trk=minTrk; - tracks[trk]->readEvent(ev); - switch (ev->command) - { - case (MIDI_NOTEON) : - if (ev->vel==0) na->add((ulong)minTime,ev->chn,0, ev->note); - else na->add((ulong)minTime,ev->chn,1,ev->note); - break; - case (MIDI_NOTEOFF) : - na->add((ulong)minTime,ev->chn,0, ev->note); - break; - case (MIDI_PGM_CHANGE) : - na->add((ulong)minTime,ev->chn, 2,ev->patch); - break; - case (MIDI_SYSTEM_PREFIX) : - { - if ((ev->command|ev->chn)==META_EVENT) - { - switch (ev->d1) - { - case (1) : - case (5) : - { - if (pspev!=NULL) - { - pspev->absmilliseconds=(ulong)minTime; - pspev->type=ev->d1; - pspev->id=spev_id++; -#ifdef PLAYERDEBUG - printf("ev->length %ld\n",ev->length); - -#endif - strncpy(pspev->text,(char *)ev->data, - (ev->length>= sizeof(lasttext))? sizeof(lasttext)-1 : (ev->length) ); - pspev->text[(ev->length>= sizeof(lasttext))? sizeof(lasttext)-1:(ev->length)]=0; -#ifdef PLAYERDEBUG - printf("(%s)(%s)\n",pspev->text,lasttext); -#endif -#ifdef REMOVEDUPSTRINGS - if ((strcmp(pspev->text,lasttext)!=0)||(pspev->absmilliseconds!=lasttexttime)||(pspev->type!=lasttexttype)) - { - lasttexttime=pspev->absmilliseconds; - lasttexttype=pspev->type; - strncpy(lasttext, pspev->text, 1024); - lasttext[sizeof(lasttext)-1] = 0; -#endif - pspev->next=new SpecialEvent; -#ifdef PLAYERDEBUG - if (pspev->next==NULL) printf("pspev->next=NULL\n"); -#endif - pspev=pspev->next; -#ifdef REMOVEDUPSTRINGS - } -#endif - } - } - break; - case (ME_SET_TEMPO) : - { - if (pspev!=NULL) - { - pspev->absmilliseconds=(ulong)minTime; - pspev->type=3; - pspev->id=spev_id++; - tempo=(ulong)(((ev->data[0]<<16)|(ev->data[1]<<8)|(ev->data[2])) * ctl->ratioTempo); - pspev->tempo=tempo; - if (firsttempo==0) firsttempo=tempo; - for (j=0;jntracks;j++) - { - tracks[j]->changeTempo(tempo); - } - pspev->next=new SpecialEvent; - pspev=pspev->next; - } - } - break; - case (ME_TIME_SIGNATURE) : - { - if (pspev!=NULL) - { - pspev->absmilliseconds=(ulong)minTime; - pspev->type=6; - pspev->id=spev_id++; - pspev->num=ev->d2; - pspev->den=ev->d3; - pspev->next=new SpecialEvent; - pspev=pspev->next; - } - } - break; - } - } - } - break; - } - } - - delete ev; - pspev->type=0; - pspev->absmilliseconds=(ulong)prevms; - pspev->next=NULL; - if (firsttempo==0) firsttempo=tempo; - ctl->tempo=firsttempo; - - //writeSPEV(); - for (int i=0;intracks;i++) - { - tracks[i]->init(); - } -} - -/* -NoteArray *MidiPlayer::parseNotes(void) -{ -#ifdef PLAYERDEBUG - printf("player::Parsing Notes...\n"); -#endif - NoteArray *na=new NoteArray(); - int trk; - int minTrk; - double minTime=0; - double maxTime; - for (int i=0;intracks;i++) - { - tracks[i]->init(); - }; - ulong tempo=1000000; - ulong tmp; - Midi_event *ev=new Midi_event; - //ulong mspass; - double prevms=0; - int j; - int parsing=1; - while (parsing) - { - prevms=minTime; - trk=0; - minTrk=0; - maxTime=minTime + 2 * 60000L; - minTime=maxTime; - while (trkntracks) - { - if (tracks[trk]->absMsOfNextEvent()absMsOfNextEvent(); - }; - trk++; - }; - if ((minTime==maxTime)) - { - parsing=0; -#ifdef PLAYERDEBUG - printf("END of parsing\n"); -#endif - } - else - { - // mspass=(ulong)(minTime-prevms); - trk=0; - while (trkntracks) - { - tracks[trk]->currentMs(minTime); - trk++; - }; - }; - trk=minTrk; - tracks[trk]->readEvent(ev); - if (ev->command==MIDI_NOTEON) - { - if (ev->vel==0) {printf("note off at %g\n",minTime);na->add((ulong)minTime,ev->chn,0, ev->note);} - else {printf("note on at %g\n",minTime);na->add((ulong)minTime,ev->chn,1,ev->note);} - } - else - if (ev->command==MIDI_NOTEOFF) na->add((ulong)minTime,ev->chn,0, ev->note); - if (ev->command==MIDI_PGM_CHANGE) na->add((ulong)minTime,ev->chn, 2,ev->patch); - if (ev->command==MIDI_SYSTEM_PREFIX) - { - if (((ev->command|ev->chn)==META_EVENT)&&(ev->d1==ME_SET_TEMPO)) - { - tempo=(ev->data[0]<<16)|(ev->data[1]<<8)|(ev->data[2]); - for (j=0;jntracks;j++) - { - tracks[j]->changeTempo(tempo); - }; - }; - }; - - }; - - delete ev; - for (int i=0;intracks;i++) - { - tracks[i]->init(); - }; - return na; -}; -*/ - -void MidiPlayer::play(bool calloutput,void output(void)) -{ -#ifdef PLAYERDEBUG - printf("Playing...\n"); -#endif - - if (midi->midiPorts()+midi->synthDevices()==0) - { - fprintf(stderr,"Player :: There are no midi ports !\n"); - ctl->error=1; - return; - } - - midi->openDev(); - if (midi->ok()==0) - { - fprintf(stderr,"Player :: Couldn't play !\n"); - ctl->error=1; - return; - } - midi->setVolumePercentage(ctl->volumepercentage); - midi->initDev(); - // parsePatchesUsed(tracks,info,ctl->gm); - midi->setPatchesToUse(info->patchesUsed); - - int trk; - int minTrk; - double minTime=0; - double maxTime; - int i; - ulong tempo=(ulong)(500000 * ctl->ratioTempo); - for (i=0;intracks;i++) - { - tracks[i]->init(); - tracks[i]->changeTempo(tempo); - } - - midi->tmrStart(info->ticksPerCuarterNote); - MidiEvent *ev=new MidiEvent; - ctl->ev=ev; - ctl->ticksTotal=info->ticksTotal; - ctl->ticksPlayed=0; - //ctl->millisecsPlayed=0; - ulong ticksplayed=0; - double absTimeAtChangeTempo=0; - double absTime=0; - double diffTime=0; - MidiStatus *midistat; - //ulong mspass; - double prevms=0; - int j; - int halt=0; - ctl->tempo=tempo; - ctl->num=4; - ctl->den=4; - int playing; - ctl->paused=0; - if ((ctl->message!=0)&&(ctl->message & PLAYER_SETPOS)) - { - ctl->moving=1; - ctl->message&=~PLAYER_SETPOS; - midi->sync(1); - midi->tmrStop(); - midi->closeDev(); - midistat = new MidiStatus(); - setPos(ctl->gotomsec,midistat); - minTime=ctl->gotomsec; - prevms=(ulong)minTime; - midi->openDev(); - midi->tmrStart(info->ticksPerCuarterNote); - diffTime=ctl->gotomsec; - midistat->sendData(midi,ctl->gm); - delete midistat; - midi->setPatchesToUse(info->patchesUsed); - ctl->moving=0; - } else - for (i=0;i<16;i++) - { - if (ctl->forcepgm[i]) - { - midi->chnPatchChange(i, ctl->pgm[i]); - } - } - - timeval begintv; - gettimeofday(&begintv, NULL); - ctl->beginmillisec=begintv.tv_sec*1000+begintv.tv_usec/1000; - ctl->OK=1; - ctl->playing=playing=1; - - while (playing) - { - /* - if (ctl->message!=0) - { - if (ctl->message & PLAYER_DOPAUSE) - { - diffTime=minTime; - ctl->message&=~PLAYER_DOPAUSE; - midi->sync(1); - midi->tmrStop(); - ctl->paused=1; - midi->closeDev(); - while ((ctl->paused)&&(!(ctl->message&PLAYER_DOSTOP)) - &&(!(ctl->message&PLAYER_HALT))) sleep(1); - midi->openDev(); - midi->tmrStart(); - ctl->OK=1; - printf("Continue playing ... \n"); - }; - if (ctl->message & PLAYER_DOSTOP) - { - ctl->message&=~PLAYER_DOSTOP; - playing=0; - }; - if (ctl->message & PLAYER_HALT) - { - ctl->message&=~PLAYER_HALT; - playing=0; - halt=1; - }; - if (ctl->message & PLAYER_SETPOS) - { - ctl->moving=1; - ctl->message&=~PLAYER_SETPOS; - midi->sync(1); - midi->tmrStop(); - midi->closeDev(); - midistat = new midiStat(); - SetPos(ctl->gotomsec,midistat); - minTime=ctl->gotomsec; - prevms=(ulong)minTime; - midi->openDev(); - midi->tmrStart(); - diffTime=ctl->gotomsec; - ctl->moving=0; - midistat->sendData(midi,ctl->gm); - delete midistat; - ctl->OK=1; - while (ctl->OK==1) ; - ctl->moving=0; - }; - }; - */ - prevms=minTime; - // ctl->millisecsPlayed=minTime; - trk=0; - minTrk=0; - maxTime=minTime + 120000L /* milliseconds */; - minTime=maxTime; - playing=0; - while (trkntracks) - { - if (tracks[trk]->absMsOfNextEvent()absMsOfNextEvent(); - playing=1; - } - trk++; - } -#ifdef PLAYERDEBUG - printf("minTime %g\n",minTime); -#endif - // if ((minTime==maxTime)/* || (minTicks> 60000L)*/) - if (playing==0) - { - // playing=0; -#ifdef PLAYERDEBUG - printf("END of playing\n"); -#endif - } - else - { - // mspass=(ulong)(minTime-prevms); - trk=0; - while (trkntracks) - { - tracks[trk]->currentMs(minTime); - trk++; - } - midi->wait(minTime-diffTime); - } - trk=minTrk; - tracks[trk]->readEvent(ev); - switch (ev->command) - { - case (MIDI_NOTEON) : - midi->noteOn(ev->chn, ev->note, ev->vel);break; - case (MIDI_NOTEOFF): - midi->noteOff(ev->chn, ev->note, ev->vel);break; - case (MIDI_KEY_PRESSURE) : - midi->keyPressure(ev->chn, ev->note,ev->vel);break; - case (MIDI_PGM_CHANGE) : - if (!ctl->forcepgm[ev->chn]) - midi->chnPatchChange(ev->chn, (ctl->gm==1)?(ev->patch):(MT32toGM[ev->patch]));break; - case (MIDI_CHN_PRESSURE) : - midi->chnPressure(ev->chn, ev->vel);break; - case (MIDI_PITCH_BEND) : - midi->chnPitchBender(ev->chn, ev->d1,ev->d2);break; - case (MIDI_CTL_CHANGE) : - midi->chnController(ev->chn, ev->ctl,ev->d1);break; - case (MIDI_SYSTEM_PREFIX) : - if ((ev->command|ev->chn)==META_EVENT) - { - if ((ev->d1==5)||(ev->d1==1)) - { - ctl->SPEVplayed++; - } - if (ev->d1==ME_SET_TEMPO) - { - absTimeAtChangeTempo=absTime; - ticksplayed=0; - ctl->SPEVplayed++; - tempo=(ulong)(((ev->data[0]<<16)|(ev->data[1]<<8)|(ev->data[2]))*ctl->ratioTempo); -#ifdef PLAYERDEBUG - printf("Tempo : %ld %g (ratio : %g)\n",tempo,tempoToMetronomeTempo(tempo),ctl->ratioTempo); -#endif - midi->tmrSetTempo((int)tempoToMetronomeTempo(tempo)); - ctl->tempo=tempo; - for (j=0;jntracks;j++) - { - tracks[j]->changeTempo(tempo); - } - } - if (ev->d1==ME_TIME_SIGNATURE) - { - ctl->num=ev->d2; - ctl->den=ev->d3; - ctl->SPEVplayed++; - } - } - break; - } - if (calloutput) - { - midi->sync(); - output(); - } - - } - ctl->ev=NULL; - delete ev; -#ifdef PLAYERDEBUG - printf("Syncronizing ...\n"); -#endif - if (halt) - midi->sync(1); - else - midi->sync(); -#ifdef PLAYERDEBUG - printf("Closing device ...\n"); -#endif - midi->allNotesOff(); - midi->closeDev(); - ctl->playing=0; -#ifdef PLAYERDEBUG - printf("Bye...\n"); -#endif - ctl->OK=1; - ctl->finished=1; -} - - -void MidiPlayer::setPos(ulong gotomsec,MidiStatus *midistat) -{ - int trk,minTrk; - ulong tempo=(ulong)(500000 * ctl->ratioTempo); - double minTime=0,maxTime,prevms=0; - int i,j,likeplaying=1; - - MidiEvent *ev=new MidiEvent; - ctl->SPEVplayed=0; - for (i=0;intracks;i++) - { - tracks[i]->init(); - tracks[i]->changeTempo(tempo); - } - - for (i=0;i<16;i++) - { - if (ctl->forcepgm[i]) midistat->chnPatchChange(i, ctl->pgm[i]); - } - - while (likeplaying) - { - trk=0; - minTrk=0; - maxTime=minTime + 120000L; /*milliseconds (2 minutes)*/ - minTime=maxTime; - while (trkntracks) - { - if (tracks[trk]->absMsOfNextEvent()absMsOfNextEvent(); - } - trk++; - } - if (minTime==maxTime) - { - likeplaying=0; -#ifdef GENERAL_DEBUG_MESSAGES - printf("END of likeplaying\n"); -#endif - } - else - { - if (minTime>=gotomsec) - { - prevms=gotomsec; - likeplaying=0; -#ifdef GENERAL_DEBUG_MESSAGES - printf("Position reached !! \n"); -#endif - minTime=gotomsec; - } - else - { - prevms=minTime; - } - trk=0; - while (trkntracks) - { - tracks[trk]->currentMs(minTime); - trk++; - } - } - - if (likeplaying) - { - trk=minTrk; - tracks[trk]->readEvent(ev); - switch (ev->command) - { - /* case (MIDI_NOTEON) : - midistat->noteOn(ev->chn, ev->note, ev->vel);break; - case (MIDI_NOTEOFF): - midistat->noteOff(ev->chn, ev->note, ev->vel);break; - case (MIDI_KEY_PRESSURE) : - midistat->keyPressure(ev->chn, ev->note,ev->vel);break; - */ - case (MIDI_PGM_CHANGE) : - if (!ctl->forcepgm[ev->chn]) midistat->chnPatchChange(ev->chn, ev->patch);break; - case (MIDI_CHN_PRESSURE) : - midistat->chnPressure(ev->chn, ev->vel);break; - case (MIDI_PITCH_BEND) : - midistat->chnPitchBender(ev->chn, ev->d1,ev->d2);break; - case (MIDI_CTL_CHANGE) : - midistat->chnController(ev->chn, ev->ctl,ev->d1);break; - case (MIDI_SYSTEM_PREFIX) : - if ((ev->command|ev->chn)==META_EVENT) - { - if ((ev->d1==5)||(ev->d1==1)) - { - ctl->SPEVplayed++; - } - if (ev->d1==ME_SET_TEMPO) - { - ctl->SPEVplayed++; - tempo=(ulong)(((ev->data[0]<<16)|(ev->data[1]<<8)|(ev->data[2]))*ctl->ratioTempo); - - midistat->tmrSetTempo((int)tempoToMetronomeTempo(tempo)); - for (j=0;jntracks;j++) - { - tracks[j]->changeTempo(tempo); - } - } - if (ev->d1==ME_TIME_SIGNATURE) - { - ctl->num=ev->d2; - ctl->den=ev->d3; - ctl->SPEVplayed++; - } - } - break; - } - } - } - delete ev; - ctl->tempo=tempo; -} - - -void MidiPlayer::debugSpecialEvents(void) -{ - SpecialEvent *pspev=spev; - printf("**************************************\n"); - while ((pspev!=NULL)&&(pspev->type!=0)) - { - printf("t:%d ticks:%d diff:%ld abs:%ld s:%s tempo:%ld\n",pspev->type,pspev->ticks,pspev->diffmilliseconds,pspev->absmilliseconds,pspev->text,pspev->tempo); - pspev=pspev->next; - } - -} - -void MidiPlayer::setParseSong(bool b) -{ - parsesong=b; -} - -void MidiPlayer::setGenerateBeats(bool b) -{ - generatebeats=b; -} - -void MidiPlayer::setTempoRatio(double ratio) -{ - if (songLoaded) - { - ctl->ratioTempo=ratio; - parseInfoData(info,tracks,ctl->ratioTempo); - if (parsesong) - { - parseSpecialEvents(); - if (generatebeats) generateBeats(); - - } - } - else - { - ctl->tempo=(ulong)((ctl->tempo*ctl->ratioTempo)/ratio); - ctl->ratioTempo=ratio; - } - -} - -#undef T2MS -#undef MS2T diff --git a/libtdemid/player.cpp b/libtdemid/player.cpp new file mode 100644 index 000000000..1596d46f4 --- /dev/null +++ b/libtdemid/player.cpp @@ -0,0 +1,959 @@ +/************************************************************************** + + player.cpp - class MidiPlayer. Plays a set of tracks + 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 "player.h" +#include "sndcard.h" +#include "midispec.h" +#include +#include +#include +#include "midistat.h" +#include "mt32togm.h" + +//#define PLAYERDEBUG +//#define GENERAL_DEBUG_MESSAGES + +#define T2MS(ticks) (((double)ticks)*(double)60000L)/((double)tempoToMetronomeTempo(tempo)*(double)info->ticksPerCuarterNote) + +#define MS2T(ms) (((ms)*(double)tempoToMetronomeTempo(tempo)*(double)info->ticksPerCuarterNote)/((double)60000L)) + +#define REMOVEDUPSTRINGS + +MidiPlayer::MidiPlayer(DeviceManager *midi_,PlayerController *pctl) +{ + midi=midi_; + info=NULL; + tracks=NULL; + songLoaded=0; + ctl=pctl; + spev=NULL; + na=NULL; + parsesong=true; + generatebeats=false; +} + +MidiPlayer::~MidiPlayer() +{ + removeSpecialEvents(); + removeSong(); +} + +void MidiPlayer::removeSong(void) +{ + if ((songLoaded)&&(tracks!=NULL)) + { +#ifdef PLAYERDEBUG + printf("Removing song from memory\n"); +#endif + int i=0; + while (intracks) + { + if (tracks[i]!=NULL) delete tracks[i]; + i++; + } + delete tracks; + tracks=NULL; + if (info!=NULL) + { + delete info; + info=NULL; + } + } + songLoaded=0; +} + +int MidiPlayer::loadSong(const char *filename) +{ + removeSong(); +#ifdef PLAYERDEBUG + printf("Loading Song : %s\n",filename); +#endif + info=new MidiFileInfo; + int ok; + tracks=readMidiFile(filename,info,ok); + if (ok<0) return ok; + if (tracks==NULL) return -4; + + parseInfoData(info,tracks,ctl->ratioTempo); + + if (parsesong) + { + parseSpecialEvents(); + if (generatebeats) generateBeats(); + } + + songLoaded=1; + return 0; +} + +void MidiPlayer::insertBeat(SpecialEvent *ev,ulong ms,int num,int den) +{ + SpecialEvent *beat=new SpecialEvent; + beat->next=ev->next; + ev->next=beat; + beat->id=1; + beat->type=7; + beat->absmilliseconds=ms; + beat->num=num; + beat->den=den; +} + + +void MidiPlayer::generateBeats(void) +{ +#ifdef PLAYERDEBUG + printf("player::Generating Beats...\n"); +#endif + + if (spev==NULL) return; + SpecialEvent *ev=spev; + SpecialEvent *nextev=ev->next; + ulong tempo=(ulong)(500000 * ctl->ratioTempo); + int i=1; + int num=4; + int den=4; + // ulong beatstep=((double)tempo*4/(den*1000)); + // ulong beatstep=T2MS(info->ticksPerCuarterNote*(4/den)); + double ticksleft=(((double)info->ticksPerCuarterNote*4)/den); + + double beatstep=T2MS(ticksleft); + double nextbeatms=0; + double lastbeatms=0; + double measurems=0; + + while (nextev!=NULL) + { + switch (ev->type) + { + case (0): // End of list + { + };break; + case (1): // Text + case (2): // Lyrics + { + };break; + case (3): // Change Tempo + { + lastbeatms=ev->absmilliseconds; + ticksleft=MS2T(nextbeatms-lastbeatms); + tempo=ev->tempo; + nextbeatms=lastbeatms+T2MS(ticksleft); + // printf("Change at %lu to %d\n",ev->absmilliseconds,ev->tempo); + // beatstep=((double)tempo*4/(den*1000)); + beatstep=T2MS(((static_cast(info->ticksPerCuarterNote)*4)/den)); + };break; + case (6): // Change number of beats per measure + { + num=ev->num; + i=1; + den=ev->den; + // printf("Change at %lu to %d/%d\n",ev->absmilliseconds,num,den); + // beatstep=((double)tempo*4/(den*1000)); + // beatstep=T2MS(info->ticksPerCuarterNote*(4/den)); + beatstep=T2MS((((double)info->ticksPerCuarterNote*4)/den)); + nextbeatms=ev->absmilliseconds; + };break; + }; + if (nextev->absmilliseconds>nextbeatms) + { + //printf("Adding %d,%d\n",num,tot); + //printf("beat at %g , %d/%d\n",nextbeatms,i,num); + //printf(" %ld %d\n",nextev->absmilliseconds,nextev->type); + if (i == 1) { + measurems=nextbeatms; + } + insertBeat(ev, static_cast(nextbeatms), i++, num); + if (i > num) { + i=1; + } + lastbeatms=nextbeatms; + nextbeatms+=beatstep; + // nextbeatms=measurems+beatstep*i; + + ticksleft = ( (static_cast(info->ticksPerCuarterNote)*4) / den); + + } + + ev=ev->next; + nextev=ev->next; + } + + /* ev==NULL doesn't indicate the end of the song, so continue generating beats */ + + if (ev!=NULL) + { + if (ev->type==0) + { + ev=spev; + /* Looking if ev->next is NULL is not needed because + we are sure that a ev->type == 0 exists, we just have + to assure that the first spev is not the only one */ + if (ev->next!=NULL) + while (ev->next->type!=0) ev=ev->next; + } + while (nextbeatmsmillisecsTotal) + { + // printf("beat2 at %g , %d/%d\n",nextbeatms,i,num); + if (i==1) measurems=nextbeatms; + insertBeat(ev, static_cast(nextbeatms), i++, num); + if (i>num) i=1; + nextbeatms+=beatstep; + ev=ev->next; + } + } + + /* Regenerate IDs */ + + ev=spev; + i=1; + while (ev!=NULL) + { + ev->id=i++; + ev=ev->next; + } + + +#ifdef PLAYERDEBUG + printf("player::Beats Generated\n"); +#endif + +} + +void MidiPlayer::removeSpecialEvents(void) +{ + SpecialEvent * ev=spev; + while (spev!=NULL) + { + ev=spev->next; + delete spev; + spev=ev; + } + delete na; + na=0; +} + +void MidiPlayer::parseSpecialEvents(void) +{ +#ifdef PLAYERDEBUG + printf("player::Parsing...\n"); +#endif + removeSpecialEvents(); + spev=new SpecialEvent; + if (spev==NULL) return; + SpecialEvent *pspev=spev; + pspev->type=0; + pspev->ticks=0; + if (na) delete na; + na=new NoteArray(); + if (!na) { delete spev; spev=0L; return; }; + int trk; + int minTrk; + double minTime=0; + double maxTime; + ulong tempo=(ulong)(500000 * (ctl->ratioTempo)); + ulong firsttempo=0; + for (int i=0;intracks;i++) + { + tracks[i]->init(); + tracks[i]->changeTempo(tempo); + } + MidiEvent *ev=new MidiEvent; + //ulong mspass; + double prevms=0; + int spev_id=1; + int j; + int parsing=1; +#ifdef REMOVEDUPSTRINGS + char lasttext[1024]; + ulong lasttexttime=0; + lasttext[0]=0; + int lasttexttype=0; +#endif + while (parsing) + { + prevms=minTime; + trk=0; + minTrk=0; + maxTime=minTime + 2 * 60000L; + minTime=maxTime; + parsing=0; + while (trkntracks) + { + if (tracks[trk]->absMsOfNextEvent()absMsOfNextEvent(); + parsing=1; + } + trk++; + } + // if ((minTime==maxTime)) + if (parsing==0) + { + // parsing=0; +#ifdef PLAYERDEBUG + printf("END of parsing\n"); +#endif + } + else + { + // mspass=(ulong)(minTime-prevms); + trk=0; + while (trkntracks) + { + tracks[trk]->currentMs(minTime); + trk++; + } + } + trk=minTrk; + tracks[trk]->readEvent(ev); + switch (ev->command) + { + case (MIDI_NOTEON) : + if (ev->vel==0) na->add((ulong)minTime,ev->chn,0, ev->note); + else na->add((ulong)minTime,ev->chn,1,ev->note); + break; + case (MIDI_NOTEOFF) : + na->add((ulong)minTime,ev->chn,0, ev->note); + break; + case (MIDI_PGM_CHANGE) : + na->add((ulong)minTime,ev->chn, 2,ev->patch); + break; + case (MIDI_SYSTEM_PREFIX) : + { + if ((ev->command|ev->chn)==META_EVENT) + { + switch (ev->d1) + { + case (1) : + case (5) : + { + if (pspev!=NULL) + { + pspev->absmilliseconds=(ulong)minTime; + pspev->type=ev->d1; + pspev->id=spev_id++; +#ifdef PLAYERDEBUG + printf("ev->length %ld\n",ev->length); + +#endif + strncpy(pspev->text,(char *)ev->data, + (ev->length>= sizeof(lasttext))? sizeof(lasttext)-1 : (ev->length) ); + pspev->text[(ev->length>= sizeof(lasttext))? sizeof(lasttext)-1:(ev->length)]=0; +#ifdef PLAYERDEBUG + printf("(%s)(%s)\n",pspev->text,lasttext); +#endif +#ifdef REMOVEDUPSTRINGS + if ((strcmp(pspev->text,lasttext)!=0)||(pspev->absmilliseconds!=lasttexttime)||(pspev->type!=lasttexttype)) + { + lasttexttime=pspev->absmilliseconds; + lasttexttype=pspev->type; + strncpy(lasttext, pspev->text, 1024); + lasttext[sizeof(lasttext)-1] = 0; +#endif + pspev->next=new SpecialEvent; +#ifdef PLAYERDEBUG + if (pspev->next==NULL) printf("pspev->next=NULL\n"); +#endif + pspev=pspev->next; +#ifdef REMOVEDUPSTRINGS + } +#endif + } + } + break; + case (ME_SET_TEMPO) : + { + if (pspev!=NULL) + { + pspev->absmilliseconds=(ulong)minTime; + pspev->type=3; + pspev->id=spev_id++; + tempo=(ulong)(((ev->data[0]<<16)|(ev->data[1]<<8)|(ev->data[2])) * ctl->ratioTempo); + pspev->tempo=tempo; + if (firsttempo==0) firsttempo=tempo; + for (j=0;jntracks;j++) + { + tracks[j]->changeTempo(tempo); + } + pspev->next=new SpecialEvent; + pspev=pspev->next; + } + } + break; + case (ME_TIME_SIGNATURE) : + { + if (pspev!=NULL) + { + pspev->absmilliseconds=(ulong)minTime; + pspev->type=6; + pspev->id=spev_id++; + pspev->num=ev->d2; + pspev->den=ev->d3; + pspev->next=new SpecialEvent; + pspev=pspev->next; + } + } + break; + } + } + } + break; + } + } + + delete ev; + pspev->type=0; + pspev->absmilliseconds=(ulong)prevms; + pspev->next=NULL; + if (firsttempo==0) firsttempo=tempo; + ctl->tempo=firsttempo; + + //writeSPEV(); + for (int i=0;intracks;i++) + { + tracks[i]->init(); + } +} + +/* +NoteArray *MidiPlayer::parseNotes(void) +{ +#ifdef PLAYERDEBUG + printf("player::Parsing Notes...\n"); +#endif + NoteArray *na=new NoteArray(); + int trk; + int minTrk; + double minTime=0; + double maxTime; + for (int i=0;intracks;i++) + { + tracks[i]->init(); + }; + ulong tempo=1000000; + ulong tmp; + Midi_event *ev=new Midi_event; + //ulong mspass; + double prevms=0; + int j; + int parsing=1; + while (parsing) + { + prevms=minTime; + trk=0; + minTrk=0; + maxTime=minTime + 2 * 60000L; + minTime=maxTime; + while (trkntracks) + { + if (tracks[trk]->absMsOfNextEvent()absMsOfNextEvent(); + }; + trk++; + }; + if ((minTime==maxTime)) + { + parsing=0; +#ifdef PLAYERDEBUG + printf("END of parsing\n"); +#endif + } + else + { + // mspass=(ulong)(minTime-prevms); + trk=0; + while (trkntracks) + { + tracks[trk]->currentMs(minTime); + trk++; + }; + }; + trk=minTrk; + tracks[trk]->readEvent(ev); + if (ev->command==MIDI_NOTEON) + { + if (ev->vel==0) {printf("note off at %g\n",minTime);na->add((ulong)minTime,ev->chn,0, ev->note);} + else {printf("note on at %g\n",minTime);na->add((ulong)minTime,ev->chn,1,ev->note);} + } + else + if (ev->command==MIDI_NOTEOFF) na->add((ulong)minTime,ev->chn,0, ev->note); + if (ev->command==MIDI_PGM_CHANGE) na->add((ulong)minTime,ev->chn, 2,ev->patch); + if (ev->command==MIDI_SYSTEM_PREFIX) + { + if (((ev->command|ev->chn)==META_EVENT)&&(ev->d1==ME_SET_TEMPO)) + { + tempo=(ev->data[0]<<16)|(ev->data[1]<<8)|(ev->data[2]); + for (j=0;jntracks;j++) + { + tracks[j]->changeTempo(tempo); + }; + }; + }; + + }; + + delete ev; + for (int i=0;intracks;i++) + { + tracks[i]->init(); + }; + return na; +}; +*/ + +void MidiPlayer::play(bool calloutput,void output(void)) +{ +#ifdef PLAYERDEBUG + printf("Playing...\n"); +#endif + + if (midi->midiPorts()+midi->synthDevices()==0) + { + fprintf(stderr,"Player :: There are no midi ports !\n"); + ctl->error=1; + return; + } + + midi->openDev(); + if (midi->ok()==0) + { + fprintf(stderr,"Player :: Couldn't play !\n"); + ctl->error=1; + return; + } + midi->setVolumePercentage(ctl->volumepercentage); + midi->initDev(); + // parsePatchesUsed(tracks,info,ctl->gm); + midi->setPatchesToUse(info->patchesUsed); + + int trk; + int minTrk; + double minTime=0; + double maxTime; + int i; + ulong tempo=(ulong)(500000 * ctl->ratioTempo); + for (i=0;intracks;i++) + { + tracks[i]->init(); + tracks[i]->changeTempo(tempo); + } + + midi->tmrStart(info->ticksPerCuarterNote); + MidiEvent *ev=new MidiEvent; + ctl->ev=ev; + ctl->ticksTotal=info->ticksTotal; + ctl->ticksPlayed=0; + //ctl->millisecsPlayed=0; + ulong ticksplayed=0; + double absTimeAtChangeTempo=0; + double absTime=0; + double diffTime=0; + MidiStatus *midistat; + //ulong mspass; + double prevms=0; + int j; + int halt=0; + ctl->tempo=tempo; + ctl->num=4; + ctl->den=4; + int playing; + ctl->paused=0; + if ((ctl->message!=0)&&(ctl->message & PLAYER_SETPOS)) + { + ctl->moving=1; + ctl->message&=~PLAYER_SETPOS; + midi->sync(1); + midi->tmrStop(); + midi->closeDev(); + midistat = new MidiStatus(); + setPos(ctl->gotomsec,midistat); + minTime=ctl->gotomsec; + prevms=(ulong)minTime; + midi->openDev(); + midi->tmrStart(info->ticksPerCuarterNote); + diffTime=ctl->gotomsec; + midistat->sendData(midi,ctl->gm); + delete midistat; + midi->setPatchesToUse(info->patchesUsed); + ctl->moving=0; + } else + for (i=0;i<16;i++) + { + if (ctl->forcepgm[i]) + { + midi->chnPatchChange(i, ctl->pgm[i]); + } + } + + timeval begintv; + gettimeofday(&begintv, NULL); + ctl->beginmillisec=begintv.tv_sec*1000+begintv.tv_usec/1000; + ctl->OK=1; + ctl->playing=playing=1; + + while (playing) + { + /* + if (ctl->message!=0) + { + if (ctl->message & PLAYER_DOPAUSE) + { + diffTime=minTime; + ctl->message&=~PLAYER_DOPAUSE; + midi->sync(1); + midi->tmrStop(); + ctl->paused=1; + midi->closeDev(); + while ((ctl->paused)&&(!(ctl->message&PLAYER_DOSTOP)) + &&(!(ctl->message&PLAYER_HALT))) sleep(1); + midi->openDev(); + midi->tmrStart(); + ctl->OK=1; + printf("Continue playing ... \n"); + }; + if (ctl->message & PLAYER_DOSTOP) + { + ctl->message&=~PLAYER_DOSTOP; + playing=0; + }; + if (ctl->message & PLAYER_HALT) + { + ctl->message&=~PLAYER_HALT; + playing=0; + halt=1; + }; + if (ctl->message & PLAYER_SETPOS) + { + ctl->moving=1; + ctl->message&=~PLAYER_SETPOS; + midi->sync(1); + midi->tmrStop(); + midi->closeDev(); + midistat = new midiStat(); + SetPos(ctl->gotomsec,midistat); + minTime=ctl->gotomsec; + prevms=(ulong)minTime; + midi->openDev(); + midi->tmrStart(); + diffTime=ctl->gotomsec; + ctl->moving=0; + midistat->sendData(midi,ctl->gm); + delete midistat; + ctl->OK=1; + while (ctl->OK==1) ; + ctl->moving=0; + }; + }; + */ + prevms=minTime; + // ctl->millisecsPlayed=minTime; + trk=0; + minTrk=0; + maxTime=minTime + 120000L /* milliseconds */; + minTime=maxTime; + playing=0; + while (trkntracks) + { + if (tracks[trk]->absMsOfNextEvent()absMsOfNextEvent(); + playing=1; + } + trk++; + } +#ifdef PLAYERDEBUG + printf("minTime %g\n",minTime); +#endif + // if ((minTime==maxTime)/* || (minTicks> 60000L)*/) + if (playing==0) + { + // playing=0; +#ifdef PLAYERDEBUG + printf("END of playing\n"); +#endif + } + else + { + // mspass=(ulong)(minTime-prevms); + trk=0; + while (trkntracks) + { + tracks[trk]->currentMs(minTime); + trk++; + } + midi->wait(minTime-diffTime); + } + trk=minTrk; + tracks[trk]->readEvent(ev); + switch (ev->command) + { + case (MIDI_NOTEON) : + midi->noteOn(ev->chn, ev->note, ev->vel);break; + case (MIDI_NOTEOFF): + midi->noteOff(ev->chn, ev->note, ev->vel);break; + case (MIDI_KEY_PRESSURE) : + midi->keyPressure(ev->chn, ev->note,ev->vel);break; + case (MIDI_PGM_CHANGE) : + if (!ctl->forcepgm[ev->chn]) + midi->chnPatchChange(ev->chn, (ctl->gm==1)?(ev->patch):(MT32toGM[ev->patch]));break; + case (MIDI_CHN_PRESSURE) : + midi->chnPressure(ev->chn, ev->vel);break; + case (MIDI_PITCH_BEND) : + midi->chnPitchBender(ev->chn, ev->d1,ev->d2);break; + case (MIDI_CTL_CHANGE) : + midi->chnController(ev->chn, ev->ctl,ev->d1);break; + case (MIDI_SYSTEM_PREFIX) : + if ((ev->command|ev->chn)==META_EVENT) + { + if ((ev->d1==5)||(ev->d1==1)) + { + ctl->SPEVplayed++; + } + if (ev->d1==ME_SET_TEMPO) + { + absTimeAtChangeTempo=absTime; + ticksplayed=0; + ctl->SPEVplayed++; + tempo=(ulong)(((ev->data[0]<<16)|(ev->data[1]<<8)|(ev->data[2]))*ctl->ratioTempo); +#ifdef PLAYERDEBUG + printf("Tempo : %ld %g (ratio : %g)\n",tempo,tempoToMetronomeTempo(tempo),ctl->ratioTempo); +#endif + midi->tmrSetTempo((int)tempoToMetronomeTempo(tempo)); + ctl->tempo=tempo; + for (j=0;jntracks;j++) + { + tracks[j]->changeTempo(tempo); + } + } + if (ev->d1==ME_TIME_SIGNATURE) + { + ctl->num=ev->d2; + ctl->den=ev->d3; + ctl->SPEVplayed++; + } + } + break; + } + if (calloutput) + { + midi->sync(); + output(); + } + + } + ctl->ev=NULL; + delete ev; +#ifdef PLAYERDEBUG + printf("Syncronizing ...\n"); +#endif + if (halt) + midi->sync(1); + else + midi->sync(); +#ifdef PLAYERDEBUG + printf("Closing device ...\n"); +#endif + midi->allNotesOff(); + midi->closeDev(); + ctl->playing=0; +#ifdef PLAYERDEBUG + printf("Bye...\n"); +#endif + ctl->OK=1; + ctl->finished=1; +} + + +void MidiPlayer::setPos(ulong gotomsec,MidiStatus *midistat) +{ + int trk,minTrk; + ulong tempo=(ulong)(500000 * ctl->ratioTempo); + double minTime=0,maxTime,prevms=0; + int i,j,likeplaying=1; + + MidiEvent *ev=new MidiEvent; + ctl->SPEVplayed=0; + for (i=0;intracks;i++) + { + tracks[i]->init(); + tracks[i]->changeTempo(tempo); + } + + for (i=0;i<16;i++) + { + if (ctl->forcepgm[i]) midistat->chnPatchChange(i, ctl->pgm[i]); + } + + while (likeplaying) + { + trk=0; + minTrk=0; + maxTime=minTime + 120000L; /*milliseconds (2 minutes)*/ + minTime=maxTime; + while (trkntracks) + { + if (tracks[trk]->absMsOfNextEvent()absMsOfNextEvent(); + } + trk++; + } + if (minTime==maxTime) + { + likeplaying=0; +#ifdef GENERAL_DEBUG_MESSAGES + printf("END of likeplaying\n"); +#endif + } + else + { + if (minTime>=gotomsec) + { + prevms=gotomsec; + likeplaying=0; +#ifdef GENERAL_DEBUG_MESSAGES + printf("Position reached !! \n"); +#endif + minTime=gotomsec; + } + else + { + prevms=minTime; + } + trk=0; + while (trkntracks) + { + tracks[trk]->currentMs(minTime); + trk++; + } + } + + if (likeplaying) + { + trk=minTrk; + tracks[trk]->readEvent(ev); + switch (ev->command) + { + /* case (MIDI_NOTEON) : + midistat->noteOn(ev->chn, ev->note, ev->vel);break; + case (MIDI_NOTEOFF): + midistat->noteOff(ev->chn, ev->note, ev->vel);break; + case (MIDI_KEY_PRESSURE) : + midistat->keyPressure(ev->chn, ev->note,ev->vel);break; + */ + case (MIDI_PGM_CHANGE) : + if (!ctl->forcepgm[ev->chn]) midistat->chnPatchChange(ev->chn, ev->patch);break; + case (MIDI_CHN_PRESSURE) : + midistat->chnPressure(ev->chn, ev->vel);break; + case (MIDI_PITCH_BEND) : + midistat->chnPitchBender(ev->chn, ev->d1,ev->d2);break; + case (MIDI_CTL_CHANGE) : + midistat->chnController(ev->chn, ev->ctl,ev->d1);break; + case (MIDI_SYSTEM_PREFIX) : + if ((ev->command|ev->chn)==META_EVENT) + { + if ((ev->d1==5)||(ev->d1==1)) + { + ctl->SPEVplayed++; + } + if (ev->d1==ME_SET_TEMPO) + { + ctl->SPEVplayed++; + tempo=(ulong)(((ev->data[0]<<16)|(ev->data[1]<<8)|(ev->data[2]))*ctl->ratioTempo); + + midistat->tmrSetTempo((int)tempoToMetronomeTempo(tempo)); + for (j=0;jntracks;j++) + { + tracks[j]->changeTempo(tempo); + } + } + if (ev->d1==ME_TIME_SIGNATURE) + { + ctl->num=ev->d2; + ctl->den=ev->d3; + ctl->SPEVplayed++; + } + } + break; + } + } + } + delete ev; + ctl->tempo=tempo; +} + + +void MidiPlayer::debugSpecialEvents(void) +{ + SpecialEvent *pspev=spev; + printf("**************************************\n"); + while ((pspev!=NULL)&&(pspev->type!=0)) + { + printf("t:%d ticks:%d diff:%ld abs:%ld s:%s tempo:%ld\n",pspev->type,pspev->ticks,pspev->diffmilliseconds,pspev->absmilliseconds,pspev->text,pspev->tempo); + pspev=pspev->next; + } + +} + +void MidiPlayer::setParseSong(bool b) +{ + parsesong=b; +} + +void MidiPlayer::setGenerateBeats(bool b) +{ + generatebeats=b; +} + +void MidiPlayer::setTempoRatio(double ratio) +{ + if (songLoaded) + { + ctl->ratioTempo=ratio; + parseInfoData(info,tracks,ctl->ratioTempo); + if (parsesong) + { + parseSpecialEvents(); + if (generatebeats) generateBeats(); + + } + } + else + { + ctl->tempo=(ulong)((ctl->tempo*ctl->ratioTempo)/ratio); + ctl->ratioTempo=ratio; + } + +} + +#undef T2MS +#undef MS2T diff --git a/libtdemid/synthout.cc b/libtdemid/synthout.cc deleted file mode 100644 index 6d7ef47a1..000000000 --- a/libtdemid/synthout.cc +++ /dev/null @@ -1,211 +0,0 @@ -/************************************************************************** - - synthout.cc - class synthOut which handles the /dev/sequencer device - for synths (as AWE32) - This file is part of LibKMid 0.9.5 - Copyright (C) 1997,98 Antonio Larrosa Jimenez and P.J.Leonard - 1999,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 - -***************************************************************************/ -#include "synthout.h" -#include -#include -#include -#include "sndcard.h" -#include -#include -#include -#include -#include "awe_sup.h" -#include "midispec.h" - -#ifdef HAVE_CONFIG_H -#include -#endif - -SEQ_USE_EXTBUF(); - -SynthOut::SynthOut(int d) -{ - seqfd = -1; - devicetype=KMID_SYNTH; - device= d; - _ok=1; -} - -SynthOut::~SynthOut() -{ - closeDev(); -} - -void SynthOut::openDev (int sqfd) -{ - _ok=1; - seqfd = sqfd; - if (seqfd==-1) - { - printfdebug("ERROR: Could not open /dev/sequencer\n"); - return; - } -#ifdef HAVE_OSS_SUPPORT - /* - int i=1; - ioctl(seqfd,SNDCTL_SEQ_THRESHOLD,i); - printfdebug("Threshold : %d\n",i); - */ -#ifdef SYNTHOUTDEBUG - printfdebug("Number of synth devices : %d\n",ndevs); - printfdebug("Number of midi ports : %d\n",nmidiports); - printfdebug("Rate : %d\n",m_rate); -#endif - -#ifdef HAVE_AWE32 - - struct synth_info info; - - // Should really collect the possible devices and let the user choose ? - - info.device = device; - - if (ioctl (seqfd, SNDCTL_SYNTH_INFO, &info) == -1) - printfdebug(" ioctl SNDCTL_SYNTH_INFO FAILED \n"); - - if (info.synth_type == SYNTH_TYPE_SAMPLE - && info.synth_subtype == SAMPLE_TYPE_AWE32) - { - - // Enable layered patches .... - AWE_SET_CHANNEL_MODE(device,1); -#ifdef SYNTHOUTDEBUG - printfdebug(" Found AWE32 dev=%d \n",device); -#endif - } -#endif // HAVE_AWE32 -#endif // HAVE_OSS_SUPPORT - -} - -void SynthOut::closeDev (void) -{ - if (!ok()) return; - //if (seqfd>=0) close(seqfd); - seqfd=-1; -} - -void SynthOut::initDev (void) -{ -#ifdef HAVE_OSS_SUPPORT - int chn; - if (!ok()) return; - uchar gm_reset[5]={0x7e, 0x7f, 0x09, 0x01, 0xf7}; - sysex(gm_reset, sizeof(gm_reset)); - for (chn=0;chn<16;chn++) - { - chnmute[chn]=0; - chnPatchChange(chn,0); - chnPressure(chn,127); - chnPitchBender(chn, 0x00, 0x40); - chnController(chn, CTL_MAIN_VOLUME,127); - chnController(chn, CTL_EXT_EFF_DEPTH, 0); - chnController(chn, CTL_CHORUS_DEPTH, 0); - chnController(chn, 0x4a, 127); - } -#endif -} - -void SynthOut::noteOn (uchar chn, uchar note, uchar vel) -{ - if (vel==0) - { - noteOff(chn,note,vel); - } - else - { - SEQ_START_NOTE(device, map->channel(chn), - map->key(chn,chnpatch[chn],note), - vel); - } -#ifdef SYNTHOUTDEBUG - printfdebug("Note ON >\t chn : %d\tnote : %d\tvel: %d\n",chn,note,vel); -#endif -} - -void SynthOut::noteOff (uchar chn, uchar note, uchar) -{ - SEQ_STOP_NOTE(device, map->channel(chn), - map->key(chn,chnpatch[chn],note), 0); -#ifdef SYNTHOUTDEBUG - printfdebug("Note OFF >\t chn : %d\tnote : %d\tvel: %d\n",chn,note,vel); -#endif -} - -void SynthOut::keyPressure (uchar chn, uchar note, uchar vel) -{ - SEQ_KEY_PRESSURE(device, map->channel(chn), map->key(chn,chnpatch[chn],note),vel); -} - -void SynthOut::chnPatchChange (uchar chn, uchar patch) -{ - SEQ_SET_PATCH(device,map->channel(chn),map->patch(chn,patch)); - chnpatch[chn]=patch; -} - -void SynthOut::chnPressure (uchar chn, uchar vel) -{ - SEQ_CHN_PRESSURE(device, map->channel(chn) , vel); - chnpressure[chn]=vel; -} - -void SynthOut::chnPitchBender(uchar chn,uchar lsb, uchar msb) -{ - chnbender[chn]=((int)msb<<7) | (lsb & 0x7F); - SEQ_BENDER(device, map->channel(chn), chnbender[chn]); -} - -void SynthOut::chnController (uchar chn, uchar ctl, uchar v) -{ - if ((ctl==11)||(ctl==7)) - { - v=(v*volumepercentage)/100; - if (v>127) v=127; - } - - SEQ_CONTROL(device, map->channel(chn), ctl, v); - chncontroller[chn][ctl]=v; -} - -void SynthOut::sysex(uchar *, ulong ) -{ - // AWE32 doesn't respond to sysex (AFAIK) -/* -#ifndef HAVE_AWE32 - ulong i=0; - SEQ_MIDIOUT(device, MIDI_SYSTEM_PREFIX); - while (i + +***************************************************************************/ +#include "synthout.h" +#include +#include +#include +#include "sndcard.h" +#include +#include +#include +#include +#include "awe_sup.h" +#include "midispec.h" + +#ifdef HAVE_CONFIG_H +#include +#endif + +SEQ_USE_EXTBUF(); + +SynthOut::SynthOut(int d) +{ + seqfd = -1; + devicetype=KMID_SYNTH; + device= d; + _ok=1; +} + +SynthOut::~SynthOut() +{ + closeDev(); +} + +void SynthOut::openDev (int sqfd) +{ + _ok=1; + seqfd = sqfd; + if (seqfd==-1) + { + printfdebug("ERROR: Could not open /dev/sequencer\n"); + return; + } +#ifdef HAVE_OSS_SUPPORT + /* + int i=1; + ioctl(seqfd,SNDCTL_SEQ_THRESHOLD,i); + printfdebug("Threshold : %d\n",i); + */ +#ifdef SYNTHOUTDEBUG + printfdebug("Number of synth devices : %d\n",ndevs); + printfdebug("Number of midi ports : %d\n",nmidiports); + printfdebug("Rate : %d\n",m_rate); +#endif + +#ifdef HAVE_AWE32 + + struct synth_info info; + + // Should really collect the possible devices and let the user choose ? + + info.device = device; + + if (ioctl (seqfd, SNDCTL_SYNTH_INFO, &info) == -1) + printfdebug(" ioctl SNDCTL_SYNTH_INFO FAILED \n"); + + if (info.synth_type == SYNTH_TYPE_SAMPLE + && info.synth_subtype == SAMPLE_TYPE_AWE32) + { + + // Enable layered patches .... + AWE_SET_CHANNEL_MODE(device,1); +#ifdef SYNTHOUTDEBUG + printfdebug(" Found AWE32 dev=%d \n",device); +#endif + } +#endif // HAVE_AWE32 +#endif // HAVE_OSS_SUPPORT + +} + +void SynthOut::closeDev (void) +{ + if (!ok()) return; + //if (seqfd>=0) close(seqfd); + seqfd=-1; +} + +void SynthOut::initDev (void) +{ +#ifdef HAVE_OSS_SUPPORT + int chn; + if (!ok()) return; + uchar gm_reset[5]={0x7e, 0x7f, 0x09, 0x01, 0xf7}; + sysex(gm_reset, sizeof(gm_reset)); + for (chn=0;chn<16;chn++) + { + chnmute[chn]=0; + chnPatchChange(chn,0); + chnPressure(chn,127); + chnPitchBender(chn, 0x00, 0x40); + chnController(chn, CTL_MAIN_VOLUME,127); + chnController(chn, CTL_EXT_EFF_DEPTH, 0); + chnController(chn, CTL_CHORUS_DEPTH, 0); + chnController(chn, 0x4a, 127); + } +#endif +} + +void SynthOut::noteOn (uchar chn, uchar note, uchar vel) +{ + if (vel==0) + { + noteOff(chn,note,vel); + } + else + { + SEQ_START_NOTE(device, map->channel(chn), + map->key(chn,chnpatch[chn],note), + vel); + } +#ifdef SYNTHOUTDEBUG + printfdebug("Note ON >\t chn : %d\tnote : %d\tvel: %d\n",chn,note,vel); +#endif +} + +void SynthOut::noteOff (uchar chn, uchar note, uchar) +{ + SEQ_STOP_NOTE(device, map->channel(chn), + map->key(chn,chnpatch[chn],note), 0); +#ifdef SYNTHOUTDEBUG + printfdebug("Note OFF >\t chn : %d\tnote : %d\tvel: %d\n",chn,note,vel); +#endif +} + +void SynthOut::keyPressure (uchar chn, uchar note, uchar vel) +{ + SEQ_KEY_PRESSURE(device, map->channel(chn), map->key(chn,chnpatch[chn],note),vel); +} + +void SynthOut::chnPatchChange (uchar chn, uchar patch) +{ + SEQ_SET_PATCH(device,map->channel(chn),map->patch(chn,patch)); + chnpatch[chn]=patch; +} + +void SynthOut::chnPressure (uchar chn, uchar vel) +{ + SEQ_CHN_PRESSURE(device, map->channel(chn) , vel); + chnpressure[chn]=vel; +} + +void SynthOut::chnPitchBender(uchar chn,uchar lsb, uchar msb) +{ + chnbender[chn]=((int)msb<<7) | (lsb & 0x7F); + SEQ_BENDER(device, map->channel(chn), chnbender[chn]); +} + +void SynthOut::chnController (uchar chn, uchar ctl, uchar v) +{ + if ((ctl==11)||(ctl==7)) + { + v=(v*volumepercentage)/100; + if (v>127) v=127; + } + + SEQ_CONTROL(device, map->channel(chn), ctl, v); + chncontroller[chn][ctl]=v; +} + +void SynthOut::sysex(uchar *, ulong ) +{ + // AWE32 doesn't respond to sysex (AFAIK) +/* +#ifndef HAVE_AWE32 + ulong i=0; + SEQ_MIDIOUT(device, MIDI_SYSTEM_PREFIX); + while (i -#include -#include - -int main (int , char **) -{ - printf("Libtdemid test2 . (C) 2000 Antonio Larrosa Jimenez . Malaga (Spain)\n"); - printf("Using libtdemid from a simple C++ application\n"); - - KMidSimpleAPI::kMidInit(); - KMidSimpleAPI::kMidLoad("Kathzy.mid"); - KMidSimpleAPI::kMidPlay(); - - for (int i=0;i<30;i++) - { - printf("%d/30 seconds\n",i+1); - sleep(1); - }; - - KMidSimpleAPI::kMidStop(); - KMidSimpleAPI::kMidDestruct(); - - return 0; -}; - diff --git a/libtdemid/tests/apitest.cpp b/libtdemid/tests/apitest.cpp new file mode 100644 index 000000000..7f370331e --- /dev/null +++ b/libtdemid/tests/apitest.cpp @@ -0,0 +1,25 @@ +#include +#include +#include + +int main (int , char **) +{ + printf("Libtdemid test2 . (C) 2000 Antonio Larrosa Jimenez . Malaga (Spain)\n"); + printf("Using libtdemid from a simple C++ application\n"); + + KMidSimpleAPI::kMidInit(); + KMidSimpleAPI::kMidLoad("Kathzy.mid"); + KMidSimpleAPI::kMidPlay(); + + for (int i=0;i<30;i++) + { + printf("%d/30 seconds\n",i+1); + sleep(1); + }; + + KMidSimpleAPI::kMidStop(); + KMidSimpleAPI::kMidDestruct(); + + return 0; +}; + diff --git a/libtdemid/tests/notesoff.cc b/libtdemid/tests/notesoff.cc deleted file mode 100644 index 15e00bd6c..000000000 --- a/libtdemid/tests/notesoff.cc +++ /dev/null @@ -1,24 +0,0 @@ -#include -#include -#include -#include - -int main (int , char **) -{ - printf("Libtdemid Notes Off . (C) 2000 Antonio Larrosa Jimenez . Malaga (Spain)\n"); - printf("Using libtdemid from a simple C++ application\n"); - - KMidSimpleAPI::kMidInit(); - - kMid.midi->checkInit(); - kMid.midi->openDev(); - kMid.midi->initDev(); - - kMid.midi->allNotesOff(); - kMid.midi->closeDev(); - - KMidSimpleAPI::kMidDestruct(); - - return 0; -}; - diff --git a/libtdemid/tests/notesoff.cpp b/libtdemid/tests/notesoff.cpp new file mode 100644 index 000000000..15e00bd6c --- /dev/null +++ b/libtdemid/tests/notesoff.cpp @@ -0,0 +1,24 @@ +#include +#include +#include +#include + +int main (int , char **) +{ + printf("Libtdemid Notes Off . (C) 2000 Antonio Larrosa Jimenez . Malaga (Spain)\n"); + printf("Using libtdemid from a simple C++ application\n"); + + KMidSimpleAPI::kMidInit(); + + kMid.midi->checkInit(); + kMid.midi->openDev(); + kMid.midi->initDev(); + + kMid.midi->allNotesOff(); + kMid.midi->closeDev(); + + KMidSimpleAPI::kMidDestruct(); + + return 0; +}; + diff --git a/libtdemid/track.cc b/libtdemid/track.cc deleted file mode 100644 index c7c858919..000000000 --- a/libtdemid/track.cc +++ /dev/null @@ -1,566 +0,0 @@ -/************************************************************************** - - track.cc - class track, which has a midi file track and its events - 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 - -***************************************************************************/ - -#include "track.h" -#include -#include "sndcard.h" -#include "midispec.h" -#include "midfile.h" - -#ifndef TRUE -#define TRUE 1 -#endif -#ifndef FALSE -#define FALSE 0 -#endif - -#define T2MS(ticks) (((double)ticks)*(double)60000L)/((double)tempoToMetronomeTempo(tempo)*(double)tPCN) - -#define MS2T(ms) (((ms)*(double)tempoToMetronomeTempo(tempo)*(double)tPCN)/((double)60000L)) - -#define PEDANTIC_TRACK -#define CHANGETEMPO_ONLY_IN_TRACK0 -//#define TRACKDEBUG -//#define TRACKDEBUG2 - -MidiTrack::MidiTrack(FILE *file,int tpcn,int Id) -{ - id=Id; - tPCN=tpcn; - currentpos=0; - size=0; - data=0L; - tempo=1000000; - if (feof(file)) - { - clear(); - return; - }; - size=readLong(file); -#ifdef TRACKDEBUG - printf("Track %d : Size %ld\n",id,size); -#endif - data=new uchar[size]; - if (data==NULL) - { - perror("track: Not enough memory ?"); - exit(-1); - } - ulong rsize=0; - if ((rsize=fread(data,1,size,file))!=size) - { - fprintf(stderr,"track (%d): File is corrupt : Couldn't load track (%ld!=%ld) !!\n", id, rsize, size); - size=rsize; - }; - /* - ptrdata=data; - current_ticks=0; - delta_ticks=readVariableLengthValue(); - wait_ticks=delta_ticks; - endoftrack=0; - */ - init(); -} - -MidiTrack::~MidiTrack() -{ - delete data; - endoftrack=1; - currentpos=0; - size=0; -} - -int MidiTrack::power2to(int i) -{ - return 1<=size) - { - endoftrack=1; - fprintf(stderr, "track (%d) : EndofTrack found by accident !\n",id); - delta_ticks = wait_ticks = ~0; - time_at_next_event=10000 * 60000L; - return 0; - } - else -#endif - { - dticks=(dticks << 7) | (*ptrdata) & 0x7F; - ptrdata++;currentpos++; - } - - } - dticks=((dticks << 7) | (*ptrdata) & 0x7F); - ptrdata++;currentpos++; - -#ifdef PEDANTIC_TRACK - - if (currentpos>=size) - { - endoftrack=1; - fprintf(stderr,"track (%d): EndofTrack found by accident 2 !\n",id); - dticks=0; - delta_ticks = wait_ticks = ~0; - time_at_next_event=10000 * 60000L; - return 0; - } -#endif -#ifdef TRACKDEBUG - printfdebug("track(%d): DTICKS : %ld\n",id,dticks); - usleep(10); -#endif - return dticks; -} - -int MidiTrack::ticksPassed (ulong ticks) -{ - if (endoftrack==1) return 0; - if (ticks>wait_ticks) - { - printfdebug("track (%d): ERROR : TICKS PASSED > WAIT TICKS\n", id); - return 1; - } - wait_ticks-=ticks; - return 0; -} - -int MidiTrack::msPassed (ulong ms) -{ - if (endoftrack==1) return 0; - current_time+=ms; - //fprintf(stderr, "old + %ld = CURR %g ", ms,current_time); - if ( current_time>time_at_next_event ) - { - fprintf(stderr, "track (%d): ERROR : MS PASSED > WAIT MS\n", id); - return 1; - } -#ifdef TRACKDEBUG - if (current_time==time_at_next_event) printfdebug("track(%d): _OK_",id); -#endif - return 0; -} - -int MidiTrack::currentMs(double ms) -{ - if (endoftrack==1) return 0; - current_time=ms; - //printfdebug("CURR %g",current_time); -#ifdef PEDANTIC_TRACK - if (current_time>time_at_next_event) - { - fprintf(stderr,"track(%d): ERROR : MS PASSED > WAIT MS\n", id); - exit(-1); - return 1; - } -#endif - return 0; -} - -void MidiTrack::readEvent(MidiEvent *ev) -{ - int i,j; - if (endoftrack==1) - { - ev->command=0; - return; - } - /* - printfdebug("...... %d\n",id); - printfdebug("current : %g , tane : %g\n",current_time,time_at_next_event); - printfdebug("......\n"); - */ - int skip_event=0; - current_time=time_at_next_event; - if (((*ptrdata)&0x80)!=0) - { - ev->command=(*ptrdata); - ptrdata++;currentpos++; - lastcommand=ev->command; - } - else - { - ev->command=lastcommand; - } - -#ifdef PEDANTIC_TRACK - if (currentpos>=size) - { - endoftrack=1; - delta_ticks = wait_ticks = ~0; - time_at_next_event=10000 * 60000L; - ev->command=MIDI_SYSTEM_PREFIX; - ev->chn=0xF; - ev->d1=ME_END_OF_TRACK; - fprintf(stderr, "track (%d): EndofTrack found by accident 3\n",id); - return; - } -#endif - - ev->chn=ev->command & 0xF; - ev->command=ev->command & 0xF0; - switch (ev->command) - { - case (MIDI_NOTEON) : - ev->note = *ptrdata;ptrdata++;currentpos++; - ev->vel = *ptrdata;ptrdata++;currentpos++; - if (ev->vel==0) - note[ev->chn][ev->note]=FALSE; - else - note[ev->chn][ev->note]=TRUE; - -#ifdef TRACKDEBUG2 - if (ev->chn==6) { - if (ev->vel==0) printfdebug("Note Onf\n"); - else printfdebug("Note On\n"); - }; -#endif - break; - case (MIDI_NOTEOFF) : -#ifdef TRACKDEBUG2 - if (ev->chn==6) printfdebug("Note Off\n"); -#endif - ev->note = *ptrdata;ptrdata++;currentpos++; - ev->vel = *ptrdata;ptrdata++;currentpos++; - note[ev->chn][ev->note]=FALSE; - - break; - case (MIDI_KEY_PRESSURE) : -#ifdef TRACKDEBUG2 - if (ev->chn==6) printfdebug ("Key press\n"); -#endif - ev->note = *ptrdata;ptrdata++;currentpos++; - ev->vel = *ptrdata;ptrdata++;currentpos++; - break; - case (MIDI_PGM_CHANGE) : -#ifdef TRACKDEBUG2 - if (ev->chn==6) printfdebug ("Pgm\n"); -#endif - ev->patch = *ptrdata;ptrdata++;currentpos++; - break; - case (MIDI_CHN_PRESSURE) : -#ifdef TRACKDEBUG2 - if (ev->chn==6) printfdebug ("Chn press\n"); -#endif - ev->vel = *ptrdata;ptrdata++;currentpos++; - break; - case (MIDI_PITCH_BEND) : -#ifdef TRACKDEBUG2 - if (ev->chn==6) printfdebug ("Pitch\n"); -#endif - ev->d1 = *ptrdata;ptrdata++;currentpos++; - ev->d2 = *ptrdata;ptrdata++;currentpos++; - break; - case (MIDI_CTL_CHANGE) : -#ifdef TRACKDEBUG2 - if (ev->chn==6) printfdebug (stderr, "Ctl\n"); -#endif - ev->ctl = *ptrdata;ptrdata++; currentpos++; - ev->d1 = *ptrdata;ptrdata++;currentpos++; - /* - switch (ev->ctl) - { - case (96) : printfdebug("RPN Increment\n");break; - case (97) : printfdebug("RPN Decrement\n");break; - case (98) : printfdebug("nRPN 98 %d\n",ev->d1);break; - case (99) : printfdebug("nRPN 99 %d\n",ev->d1);break; - case (100) : printfdebug("RPN 100 %d\n",ev->d1);break; - case (101) : printfdebug("RPN 101 %d\n",ev->d1);break; - }; - */ - break; - - case (MIDI_SYSTEM_PREFIX) : -#ifdef TRACKDEBUG2 - if (ev->chn==6) printfdebug ("Sys Prefix\n"); -#endif - switch ((ev->command|ev->chn)) - { - case (0xF0) : - case (0xF7) : - ev->length=readVariableLengthValue(); -#ifdef PEDANTIC_TRACK - if (endoftrack) - { - ev->command=MIDI_SYSTEM_PREFIX; - ev->chn=0xF; - ev->d1=ME_END_OF_TRACK; - } - else -#endif - { - ev->data=ptrdata; - ptrdata+=ev->length;currentpos+=ev->length; - } - break; - case (0xFE): - case (0xF8): - // printfdebug("Active sensing\n"); - break; - case (META_EVENT) : - ev->d1=*ptrdata;ptrdata++;currentpos++; - switch (ev->d1) - { - case (ME_END_OF_TRACK) : - i=0; - j=0; - while ((i<16)&&(note[i][j]==FALSE)) - { - j++; - if (j==128) { j=0; i++; }; - } - if (i<16) // that is, if there is any key still pressed - { - ptrdata--;currentpos--; - ev->chn=i; - ev->command=MIDI_NOTEOFF; - ev->note = j; - ev->vel = 0; - note[ev->chn][ev->note]=FALSE; - fprintf(stderr,"Note Off(simulated)\n"); - return; - } - else - { - endoftrack=1; - delta_ticks = wait_ticks = ~0; - time_at_next_event=10000 * 60000L; -#ifdef TRACKDEBUG - printfdebug("EndofTrack %d event\n",id); -#endif - } - break; - case (ME_SET_TEMPO): - ev->length=readVariableLengthValue(); -#ifdef PEDANTIC_TRACK - if (endoftrack) - { - ev->command=MIDI_SYSTEM_PREFIX; - ev->chn=0xF; - ev->d1=ME_END_OF_TRACK; - } - else -#endif - { - ev->data=ptrdata; - ptrdata+=ev->length;currentpos+=ev->length; - // tempo=((ev->data[0]<<16)|(ev->data[1]<<8)|(ev->data[2])); - // ticks_from_previous_tempochange=0; - // time_at_previous_tempochange=current_time; -#ifdef TRACKDEBUG - printfdebug("Track %d : Set Tempo : %ld\n",id,tempo); -#endif -#ifdef CHANGETEMPO_ONLY_IN_TRACK0 - if (id!=0) skip_event=1; -#endif - } - break; - case (ME_TIME_SIGNATURE) : - ev->length=*ptrdata;ptrdata++;currentpos++; - ev->d2=*ptrdata;ptrdata++;currentpos++; - ev->d3=power2to(*ptrdata);ptrdata++;currentpos++; - ev->d4=*ptrdata;ptrdata++;currentpos++; - ev->d5=*ptrdata;ptrdata++;currentpos++; -#ifdef TRACKDEBUG - printfdebug("TIME SIGNATURE :\n"); - printfdebug("%d\n",ev->d2); - printfdebug("---- %d metronome , %d number of 32nd notes per quarter note\n",ev->d4,ev->d5); - printfdebug("%d\n",ev->d3); -#endif - break; - case (ME_TRACK_SEQ_NUMBER) : - case (ME_TEXT) : - case (ME_COPYRIGHT) : - case (ME_SEQ_OR_TRACK_NAME) : - case (ME_TRACK_INSTR_NAME) : - case (ME_LYRIC) : - case (ME_MARKER) : - case (ME_CUE_POINT) : - case (ME_CHANNEL_PREFIX) : - case (ME_MIDI_PORT) : - case (ME_SMPTE_OFFSET) : - case (ME_KEY_SIGNATURE) : - ev->length=readVariableLengthValue(); -#ifdef PEDANTIC_TRACK - if (endoftrack) - { - ev->command=MIDI_SYSTEM_PREFIX; - ev->chn=0xF; - ev->d1=ME_END_OF_TRACK; - } - else -#endif - { - ev->data=ptrdata; - ptrdata+=ev->length;currentpos+=ev->length; - } - break; - default: -#ifdef GENERAL_DEBUG_MESSAGES - fprintf(stderr,"track (%d) : Default handler for meta event " \ - "0x%x\n", id, ev->d1); -#endif - ev->length=readVariableLengthValue(); -#ifdef PEDANTIC_TRACK - if (endoftrack) - { - ev->command=MIDI_SYSTEM_PREFIX; - ev->chn=0xF; - ev->d1=ME_END_OF_TRACK; - } - else -#endif - { - ev->data=ptrdata; - ptrdata+=ev->length;currentpos+=ev->length; - } - break; - } - break; - default : - fprintf(stderr,"track (%d): Default handler for system event 0x%x\n", - id, (ev->command|ev->chn)); - break; - } - break; - default : - fprintf(stderr,"track (%d): Default handler for event 0x%x\n", - id, (ev->command|ev->chn)); - break; - } -#ifdef PEDANTIC_TRACK - if (currentpos>=size) - { - endoftrack=1; - delta_ticks = wait_ticks = ~0; - time_at_next_event=10000 * 60000L; - printfdebug("track (%d): EndofTrack reached\n",id); - } -#endif - if (endoftrack==0) - { - current_ticks+=delta_ticks; - delta_ticks=readVariableLengthValue(); -#ifdef PEDANTIC_TRACK - if (endoftrack) - { - ev->command=MIDI_SYSTEM_PREFIX; - ev->chn=0xF; - ev->d1=ME_END_OF_TRACK; - return; - } -#endif - ticks_from_previous_tempochange+=delta_ticks; - - time_at_next_event=T2MS(ticks_from_previous_tempochange)+time_at_previous_tempochange; - /* - printf("tane2 : %g, ticks : %g, delta_ticks %ld, tempo : %ld\n", - time_at_next_event,ticks_from_previous_tempochange,delta_ticks,tempo); - printf("timeatprevtc %g , curr %g\n",time_at_previous_tempochange,current_time); - */ - wait_ticks=delta_ticks; - - } - if (skip_event) readEvent(ev); -} - - -void MidiTrack::clear(void) -{ - endoftrack=1; - ptrdata=data; - current_ticks=0; - currentpos=0; - - for (int i=0;i<16;i++) - for (int j=0;j<128;j++) - note[i][j]=FALSE; - - delta_ticks = wait_ticks = ~0; - time_at_previous_tempochange=0; - current_time=0; - ticks_from_previous_tempochange=0; - tempo=1000000; - time_at_next_event=10000 * 60000L; - -} - - -void MidiTrack::init(void) -{ - if (data==0L) { clear(); return; }; - endoftrack=0; - ptrdata=data; - current_ticks=0; - currentpos=0; - - for (int i=0;i<16;i++) - for (int j=0;j<128;j++) - note[i][j]=FALSE; - - delta_ticks=readVariableLengthValue(); - if (endoftrack) return; - wait_ticks=delta_ticks; - - - time_at_previous_tempochange=0; - current_time=0; - ticks_from_previous_tempochange=wait_ticks; - tempo=1000000; - time_at_next_event=T2MS(delta_ticks); - //printf("tane1 : %g\n",time_at_next_event); -} - -void MidiTrack::changeTempo(ulong t) -{ - if (endoftrack==1) return; - if (tempo==t) return; - double ticks; - time_at_previous_tempochange=current_time; - ticks=MS2T(time_at_next_event-current_time); - tempo=t; - time_at_next_event=T2MS(ticks)+current_time; - ticks_from_previous_tempochange=ticks; - -} - -/* -double MidiTrack::absMsOfNextEvent (void) -{ - //printf("%d : %g\n",id,time_at_next_event); - return time_at_next_event; -} -*/ - -#undef T2MS -#undef MS2T diff --git a/libtdemid/track.cpp b/libtdemid/track.cpp new file mode 100644 index 000000000..44375b637 --- /dev/null +++ b/libtdemid/track.cpp @@ -0,0 +1,566 @@ +/************************************************************************** + + track.cpp - class track, which has a midi file track and its events + 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 + +***************************************************************************/ + +#include "track.h" +#include +#include "sndcard.h" +#include "midispec.h" +#include "midfile.h" + +#ifndef TRUE +#define TRUE 1 +#endif +#ifndef FALSE +#define FALSE 0 +#endif + +#define T2MS(ticks) (((double)ticks)*(double)60000L)/((double)tempoToMetronomeTempo(tempo)*(double)tPCN) + +#define MS2T(ms) (((ms)*(double)tempoToMetronomeTempo(tempo)*(double)tPCN)/((double)60000L)) + +#define PEDANTIC_TRACK +#define CHANGETEMPO_ONLY_IN_TRACK0 +//#define TRACKDEBUG +//#define TRACKDEBUG2 + +MidiTrack::MidiTrack(FILE *file,int tpcn,int Id) +{ + id=Id; + tPCN=tpcn; + currentpos=0; + size=0; + data=0L; + tempo=1000000; + if (feof(file)) + { + clear(); + return; + }; + size=readLong(file); +#ifdef TRACKDEBUG + printf("Track %d : Size %ld\n",id,size); +#endif + data=new uchar[size]; + if (data==NULL) + { + perror("track: Not enough memory ?"); + exit(-1); + } + ulong rsize=0; + if ((rsize=fread(data,1,size,file))!=size) + { + fprintf(stderr,"track (%d): File is corrupt : Couldn't load track (%ld!=%ld) !!\n", id, rsize, size); + size=rsize; + }; + /* + ptrdata=data; + current_ticks=0; + delta_ticks=readVariableLengthValue(); + wait_ticks=delta_ticks; + endoftrack=0; + */ + init(); +} + +MidiTrack::~MidiTrack() +{ + delete data; + endoftrack=1; + currentpos=0; + size=0; +} + +int MidiTrack::power2to(int i) +{ + return 1<=size) + { + endoftrack=1; + fprintf(stderr, "track (%d) : EndofTrack found by accident !\n",id); + delta_ticks = wait_ticks = ~0; + time_at_next_event=10000 * 60000L; + return 0; + } + else +#endif + { + dticks=(dticks << 7) | (*ptrdata) & 0x7F; + ptrdata++;currentpos++; + } + + } + dticks=((dticks << 7) | (*ptrdata) & 0x7F); + ptrdata++;currentpos++; + +#ifdef PEDANTIC_TRACK + + if (currentpos>=size) + { + endoftrack=1; + fprintf(stderr,"track (%d): EndofTrack found by accident 2 !\n",id); + dticks=0; + delta_ticks = wait_ticks = ~0; + time_at_next_event=10000 * 60000L; + return 0; + } +#endif +#ifdef TRACKDEBUG + printfdebug("track(%d): DTICKS : %ld\n",id,dticks); + usleep(10); +#endif + return dticks; +} + +int MidiTrack::ticksPassed (ulong ticks) +{ + if (endoftrack==1) return 0; + if (ticks>wait_ticks) + { + printfdebug("track (%d): ERROR : TICKS PASSED > WAIT TICKS\n", id); + return 1; + } + wait_ticks-=ticks; + return 0; +} + +int MidiTrack::msPassed (ulong ms) +{ + if (endoftrack==1) return 0; + current_time+=ms; + //fprintf(stderr, "old + %ld = CURR %g ", ms,current_time); + if ( current_time>time_at_next_event ) + { + fprintf(stderr, "track (%d): ERROR : MS PASSED > WAIT MS\n", id); + return 1; + } +#ifdef TRACKDEBUG + if (current_time==time_at_next_event) printfdebug("track(%d): _OK_",id); +#endif + return 0; +} + +int MidiTrack::currentMs(double ms) +{ + if (endoftrack==1) return 0; + current_time=ms; + //printfdebug("CURR %g",current_time); +#ifdef PEDANTIC_TRACK + if (current_time>time_at_next_event) + { + fprintf(stderr,"track(%d): ERROR : MS PASSED > WAIT MS\n", id); + exit(-1); + return 1; + } +#endif + return 0; +} + +void MidiTrack::readEvent(MidiEvent *ev) +{ + int i,j; + if (endoftrack==1) + { + ev->command=0; + return; + } + /* + printfdebug("...... %d\n",id); + printfdebug("current : %g , tane : %g\n",current_time,time_at_next_event); + printfdebug("......\n"); + */ + int skip_event=0; + current_time=time_at_next_event; + if (((*ptrdata)&0x80)!=0) + { + ev->command=(*ptrdata); + ptrdata++;currentpos++; + lastcommand=ev->command; + } + else + { + ev->command=lastcommand; + } + +#ifdef PEDANTIC_TRACK + if (currentpos>=size) + { + endoftrack=1; + delta_ticks = wait_ticks = ~0; + time_at_next_event=10000 * 60000L; + ev->command=MIDI_SYSTEM_PREFIX; + ev->chn=0xF; + ev->d1=ME_END_OF_TRACK; + fprintf(stderr, "track (%d): EndofTrack found by accident 3\n",id); + return; + } +#endif + + ev->chn=ev->command & 0xF; + ev->command=ev->command & 0xF0; + switch (ev->command) + { + case (MIDI_NOTEON) : + ev->note = *ptrdata;ptrdata++;currentpos++; + ev->vel = *ptrdata;ptrdata++;currentpos++; + if (ev->vel==0) + note[ev->chn][ev->note]=FALSE; + else + note[ev->chn][ev->note]=TRUE; + +#ifdef TRACKDEBUG2 + if (ev->chn==6) { + if (ev->vel==0) printfdebug("Note Onf\n"); + else printfdebug("Note On\n"); + }; +#endif + break; + case (MIDI_NOTEOFF) : +#ifdef TRACKDEBUG2 + if (ev->chn==6) printfdebug("Note Off\n"); +#endif + ev->note = *ptrdata;ptrdata++;currentpos++; + ev->vel = *ptrdata;ptrdata++;currentpos++; + note[ev->chn][ev->note]=FALSE; + + break; + case (MIDI_KEY_PRESSURE) : +#ifdef TRACKDEBUG2 + if (ev->chn==6) printfdebug ("Key press\n"); +#endif + ev->note = *ptrdata;ptrdata++;currentpos++; + ev->vel = *ptrdata;ptrdata++;currentpos++; + break; + case (MIDI_PGM_CHANGE) : +#ifdef TRACKDEBUG2 + if (ev->chn==6) printfdebug ("Pgm\n"); +#endif + ev->patch = *ptrdata;ptrdata++;currentpos++; + break; + case (MIDI_CHN_PRESSURE) : +#ifdef TRACKDEBUG2 + if (ev->chn==6) printfdebug ("Chn press\n"); +#endif + ev->vel = *ptrdata;ptrdata++;currentpos++; + break; + case (MIDI_PITCH_BEND) : +#ifdef TRACKDEBUG2 + if (ev->chn==6) printfdebug ("Pitch\n"); +#endif + ev->d1 = *ptrdata;ptrdata++;currentpos++; + ev->d2 = *ptrdata;ptrdata++;currentpos++; + break; + case (MIDI_CTL_CHANGE) : +#ifdef TRACKDEBUG2 + if (ev->chn==6) printfdebug (stderr, "Ctl\n"); +#endif + ev->ctl = *ptrdata;ptrdata++; currentpos++; + ev->d1 = *ptrdata;ptrdata++;currentpos++; + /* + switch (ev->ctl) + { + case (96) : printfdebug("RPN Increment\n");break; + case (97) : printfdebug("RPN Decrement\n");break; + case (98) : printfdebug("nRPN 98 %d\n",ev->d1);break; + case (99) : printfdebug("nRPN 99 %d\n",ev->d1);break; + case (100) : printfdebug("RPN 100 %d\n",ev->d1);break; + case (101) : printfdebug("RPN 101 %d\n",ev->d1);break; + }; + */ + break; + + case (MIDI_SYSTEM_PREFIX) : +#ifdef TRACKDEBUG2 + if (ev->chn==6) printfdebug ("Sys Prefix\n"); +#endif + switch ((ev->command|ev->chn)) + { + case (0xF0) : + case (0xF7) : + ev->length=readVariableLengthValue(); +#ifdef PEDANTIC_TRACK + if (endoftrack) + { + ev->command=MIDI_SYSTEM_PREFIX; + ev->chn=0xF; + ev->d1=ME_END_OF_TRACK; + } + else +#endif + { + ev->data=ptrdata; + ptrdata+=ev->length;currentpos+=ev->length; + } + break; + case (0xFE): + case (0xF8): + // printfdebug("Active sensing\n"); + break; + case (META_EVENT) : + ev->d1=*ptrdata;ptrdata++;currentpos++; + switch (ev->d1) + { + case (ME_END_OF_TRACK) : + i=0; + j=0; + while ((i<16)&&(note[i][j]==FALSE)) + { + j++; + if (j==128) { j=0; i++; }; + } + if (i<16) // that is, if there is any key still pressed + { + ptrdata--;currentpos--; + ev->chn=i; + ev->command=MIDI_NOTEOFF; + ev->note = j; + ev->vel = 0; + note[ev->chn][ev->note]=FALSE; + fprintf(stderr,"Note Off(simulated)\n"); + return; + } + else + { + endoftrack=1; + delta_ticks = wait_ticks = ~0; + time_at_next_event=10000 * 60000L; +#ifdef TRACKDEBUG + printfdebug("EndofTrack %d event\n",id); +#endif + } + break; + case (ME_SET_TEMPO): + ev->length=readVariableLengthValue(); +#ifdef PEDANTIC_TRACK + if (endoftrack) + { + ev->command=MIDI_SYSTEM_PREFIX; + ev->chn=0xF; + ev->d1=ME_END_OF_TRACK; + } + else +#endif + { + ev->data=ptrdata; + ptrdata+=ev->length;currentpos+=ev->length; + // tempo=((ev->data[0]<<16)|(ev->data[1]<<8)|(ev->data[2])); + // ticks_from_previous_tempochange=0; + // time_at_previous_tempochange=current_time; +#ifdef TRACKDEBUG + printfdebug("Track %d : Set Tempo : %ld\n",id,tempo); +#endif +#ifdef CHANGETEMPO_ONLY_IN_TRACK0 + if (id!=0) skip_event=1; +#endif + } + break; + case (ME_TIME_SIGNATURE) : + ev->length=*ptrdata;ptrdata++;currentpos++; + ev->d2=*ptrdata;ptrdata++;currentpos++; + ev->d3=power2to(*ptrdata);ptrdata++;currentpos++; + ev->d4=*ptrdata;ptrdata++;currentpos++; + ev->d5=*ptrdata;ptrdata++;currentpos++; +#ifdef TRACKDEBUG + printfdebug("TIME SIGNATURE :\n"); + printfdebug("%d\n",ev->d2); + printfdebug("---- %d metronome , %d number of 32nd notes per quarter note\n",ev->d4,ev->d5); + printfdebug("%d\n",ev->d3); +#endif + break; + case (ME_TRACK_SEQ_NUMBER) : + case (ME_TEXT) : + case (ME_COPYRIGHT) : + case (ME_SEQ_OR_TRACK_NAME) : + case (ME_TRACK_INSTR_NAME) : + case (ME_LYRIC) : + case (ME_MARKER) : + case (ME_CUE_POINT) : + case (ME_CHANNEL_PREFIX) : + case (ME_MIDI_PORT) : + case (ME_SMPTE_OFFSET) : + case (ME_KEY_SIGNATURE) : + ev->length=readVariableLengthValue(); +#ifdef PEDANTIC_TRACK + if (endoftrack) + { + ev->command=MIDI_SYSTEM_PREFIX; + ev->chn=0xF; + ev->d1=ME_END_OF_TRACK; + } + else +#endif + { + ev->data=ptrdata; + ptrdata+=ev->length;currentpos+=ev->length; + } + break; + default: +#ifdef GENERAL_DEBUG_MESSAGES + fprintf(stderr,"track (%d) : Default handler for meta event " \ + "0x%x\n", id, ev->d1); +#endif + ev->length=readVariableLengthValue(); +#ifdef PEDANTIC_TRACK + if (endoftrack) + { + ev->command=MIDI_SYSTEM_PREFIX; + ev->chn=0xF; + ev->d1=ME_END_OF_TRACK; + } + else +#endif + { + ev->data=ptrdata; + ptrdata+=ev->length;currentpos+=ev->length; + } + break; + } + break; + default : + fprintf(stderr,"track (%d): Default handler for system event 0x%x\n", + id, (ev->command|ev->chn)); + break; + } + break; + default : + fprintf(stderr,"track (%d): Default handler for event 0x%x\n", + id, (ev->command|ev->chn)); + break; + } +#ifdef PEDANTIC_TRACK + if (currentpos>=size) + { + endoftrack=1; + delta_ticks = wait_ticks = ~0; + time_at_next_event=10000 * 60000L; + printfdebug("track (%d): EndofTrack reached\n",id); + } +#endif + if (endoftrack==0) + { + current_ticks+=delta_ticks; + delta_ticks=readVariableLengthValue(); +#ifdef PEDANTIC_TRACK + if (endoftrack) + { + ev->command=MIDI_SYSTEM_PREFIX; + ev->chn=0xF; + ev->d1=ME_END_OF_TRACK; + return; + } +#endif + ticks_from_previous_tempochange+=delta_ticks; + + time_at_next_event=T2MS(ticks_from_previous_tempochange)+time_at_previous_tempochange; + /* + printf("tane2 : %g, ticks : %g, delta_ticks %ld, tempo : %ld\n", + time_at_next_event,ticks_from_previous_tempochange,delta_ticks,tempo); + printf("timeatprevtc %g , curr %g\n",time_at_previous_tempochange,current_time); + */ + wait_ticks=delta_ticks; + + } + if (skip_event) readEvent(ev); +} + + +void MidiTrack::clear(void) +{ + endoftrack=1; + ptrdata=data; + current_ticks=0; + currentpos=0; + + for (int i=0;i<16;i++) + for (int j=0;j<128;j++) + note[i][j]=FALSE; + + delta_ticks = wait_ticks = ~0; + time_at_previous_tempochange=0; + current_time=0; + ticks_from_previous_tempochange=0; + tempo=1000000; + time_at_next_event=10000 * 60000L; + +} + + +void MidiTrack::init(void) +{ + if (data==0L) { clear(); return; }; + endoftrack=0; + ptrdata=data; + current_ticks=0; + currentpos=0; + + for (int i=0;i<16;i++) + for (int j=0;j<128;j++) + note[i][j]=FALSE; + + delta_ticks=readVariableLengthValue(); + if (endoftrack) return; + wait_ticks=delta_ticks; + + + time_at_previous_tempochange=0; + current_time=0; + ticks_from_previous_tempochange=wait_ticks; + tempo=1000000; + time_at_next_event=T2MS(delta_ticks); + //printf("tane1 : %g\n",time_at_next_event); +} + +void MidiTrack::changeTempo(ulong t) +{ + if (endoftrack==1) return; + if (tempo==t) return; + double ticks; + time_at_previous_tempochange=current_time; + ticks=MS2T(time_at_next_event-current_time); + tempo=t; + time_at_next_event=T2MS(ticks)+current_time; + ticks_from_previous_tempochange=ticks; + +} + +/* +double MidiTrack::absMsOfNextEvent (void) +{ + //printf("%d : %g\n",id,time_at_next_event); + return time_at_next_event; +} +*/ + +#undef T2MS +#undef MS2T diff --git a/libtdemid/voiceman.cc b/libtdemid/voiceman.cc deleted file mode 100644 index 867ee6024..000000000 --- a/libtdemid/voiceman.cc +++ /dev/null @@ -1,279 +0,0 @@ -/************************************************************************** - - voiceman.cc - The VoiceManager class handles a set of voices for synths - 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 - -***************************************************************************/ - -#include "voiceman.h" -#include -#ifdef HAVE_CONFIG_H -#include -#endif - -VoiceManager::VoiceManager(int totalvoices) -{ - nvoices=totalvoices; - - FirstVoice=new voice; - FirstVoice->id=0; - FirstVoice->channel=0; - FirstVoice->note=0; - FirstVoice->used=0; - FirstVoice->prev=NULL; - - voice *ptrb=FirstVoice; - voice *ptr=NULL; - int i; - for (i=1;inext=ptr; - ptr->id=i; - ptr->channel=0; - ptr->note=0; - ptr->used=0; - ptr->prev=ptrb; - ptrb=ptr; - } - LastVoice=ptr; - LastVoice->next=NULL; - LastnotusedVoice=LastVoice; - - VoiceList=new voice *[nvoices]; - ptr=FirstVoice; - for (i=0;inext; - } - searcher_aid=new voice; -} - -VoiceManager::~VoiceManager() -{ - voice *ptr=FirstVoice; - voice *ptr2; - while (ptr!=NULL) - { - ptr2=ptr->next; - delete ptr; - ptr=ptr2; - } - FirstVoice=NULL; - LastVoice=NULL; - LastnotusedVoice=NULL; - - delete [] VoiceList; - VoiceList=NULL; - - delete searcher_aid; -} - -void VoiceManager::clearLists(void) -{ -#ifdef VOICEMANDEBUG - printf("voicemanager::cleanLists\n"); -#endif - voice *ptr=FirstVoice; - voice *ptr2=FirstVoice; - while (ptr!=NULL) - { - ptr->used=0; - ptr2=ptr; - ptr=ptr->next; - } - LastVoice=ptr2; - LastnotusedVoice=ptr2; - -} - -int VoiceManager::allocateVoice(int chn,int key) -{ - // First, we take the allocated voice out of the first place of the list - if ((LastnotusedVoice!=NULL)&&(LastnotusedVoice->id==FirstVoice->id)) - { -#ifdef VOICEMANDEBUG - printf("Used last voice !\n"); -#endif - LastnotusedVoice=NULL; - } - voice *newvoice=FirstVoice; - FirstVoice=FirstVoice->next; - FirstVoice->prev=NULL; - -#ifdef VOICEMANDEBUG - printf("Allocating id :%d\n",newvoice->id); -#endif - // then we put the allocated voice at the end of the list - LastVoice->next=newvoice; - newvoice->prev=LastVoice; - LastVoice=newvoice; - LastVoice->next=NULL; - - newvoice->channel=chn; - newvoice->note=key; - -#ifdef VOICEMANDEBUG - if (newvoice->used==1) - { - printf("Replacing voice : %d\n",newvoice->id); - } -#endif - newvoice->used=1; - - //dispStat(); - return newvoice->id; -} - -void VoiceManager::deallocateVoice(int id) -{ - voice *delvoice=VoiceList[id]; -#ifdef VOICEMANDEBUG - printf("Deallocating id :%d\n",id); -#endif - if (delvoice->id==LastVoice->id) - { - LastVoice=delvoice->prev; - LastVoice->next=NULL; - - if (LastnotusedVoice==NULL) - { - delvoice->next=FirstVoice; - FirstVoice->prev=delvoice; - FirstVoice=delvoice; - FirstVoice->prev=NULL; - LastnotusedVoice=FirstVoice; - } - else - { - if (LastnotusedVoice->next==NULL) - { - LastnotusedVoice->next=delvoice; - delvoice->prev=LastnotusedVoice; - delvoice->next=NULL; - LastnotusedVoice=delvoice; - LastVoice=delvoice; - } - else - { - delvoice->next=LastnotusedVoice->next; - delvoice->next->prev=delvoice; - delvoice->prev=LastnotusedVoice; - LastnotusedVoice->next=delvoice; - LastnotusedVoice=delvoice; - } - } - } - else - { - if (delvoice->prev!=NULL) - { - delvoice->prev->next=delvoice->next; - delvoice->next->prev=delvoice->prev; - if (LastnotusedVoice==NULL) - { - delvoice->next=FirstVoice; - FirstVoice->prev=delvoice; - FirstVoice=delvoice; - FirstVoice->prev=NULL; - LastnotusedVoice=FirstVoice; } - else - { - if (LastnotusedVoice->next==NULL) - { - LastnotusedVoice->next=delvoice; - delvoice->prev=LastnotusedVoice; - delvoice->next=NULL; - LastnotusedVoice=delvoice; - LastVoice=delvoice; - } - else - { - delvoice->next=LastnotusedVoice->next; - delvoice->next->prev=delvoice; - delvoice->prev=LastnotusedVoice; - LastnotusedVoice->next=delvoice; - LastnotusedVoice=delvoice; - } - } - } - } - delvoice->used=0; - - // dispStat(); -} - -void VoiceManager::initSearch(void) -{ - searcher=searcher_aid; - searcher_aid->prev=LastVoice; -} - -int VoiceManager::search(int chn) -{ - if (searcher==NULL) return -1; - searcher=searcher->prev; - - while (searcher!=NULL) - { - if (searcher->used==0) return -1; - if (searcher->channel==chn) - { - return searcher->id; - } - searcher=searcher->prev; - } - return -1; -} - -int VoiceManager::search(int chn,int note) -{ - if (searcher==NULL) return -1; - searcher=searcher->prev; - while ((searcher!=NULL)) - { - if (searcher->used==0) return -1; - if ((searcher->channel==chn)&&(searcher->note==note)) - { - return searcher->id; - } - searcher=searcher->prev; - } - return -1; -} - -/* -void VoiceManager::dispStat(void) -{ -#ifdef VOICEMANDEBUG - printf("Stats\n"); - voice *ptr=FirstVoice; - while (ptr!=NULL) - { - printf("Voice %d is %s\n",ptr->id,(ptr->used==0)?("off"):("on")); - ptr=ptr->next; - } - if (LastnotusedVoice!=NULL) printf("LnuV = %d\n",LastnotusedVoice->id); -#endif -} -*/ diff --git a/libtdemid/voiceman.cpp b/libtdemid/voiceman.cpp new file mode 100644 index 000000000..fddf68f0e --- /dev/null +++ b/libtdemid/voiceman.cpp @@ -0,0 +1,279 @@ +/************************************************************************** + + voiceman.cpp - The VoiceManager class handles a set of voices for synths + 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 + +***************************************************************************/ + +#include "voiceman.h" +#include +#ifdef HAVE_CONFIG_H +#include +#endif + +VoiceManager::VoiceManager(int totalvoices) +{ + nvoices=totalvoices; + + FirstVoice=new voice; + FirstVoice->id=0; + FirstVoice->channel=0; + FirstVoice->note=0; + FirstVoice->used=0; + FirstVoice->prev=NULL; + + voice *ptrb=FirstVoice; + voice *ptr=NULL; + int i; + for (i=1;inext=ptr; + ptr->id=i; + ptr->channel=0; + ptr->note=0; + ptr->used=0; + ptr->prev=ptrb; + ptrb=ptr; + } + LastVoice=ptr; + LastVoice->next=NULL; + LastnotusedVoice=LastVoice; + + VoiceList=new voice *[nvoices]; + ptr=FirstVoice; + for (i=0;inext; + } + searcher_aid=new voice; +} + +VoiceManager::~VoiceManager() +{ + voice *ptr=FirstVoice; + voice *ptr2; + while (ptr!=NULL) + { + ptr2=ptr->next; + delete ptr; + ptr=ptr2; + } + FirstVoice=NULL; + LastVoice=NULL; + LastnotusedVoice=NULL; + + delete [] VoiceList; + VoiceList=NULL; + + delete searcher_aid; +} + +void VoiceManager::clearLists(void) +{ +#ifdef VOICEMANDEBUG + printf("voicemanager::cleanLists\n"); +#endif + voice *ptr=FirstVoice; + voice *ptr2=FirstVoice; + while (ptr!=NULL) + { + ptr->used=0; + ptr2=ptr; + ptr=ptr->next; + } + LastVoice=ptr2; + LastnotusedVoice=ptr2; + +} + +int VoiceManager::allocateVoice(int chn,int key) +{ + // First, we take the allocated voice out of the first place of the list + if ((LastnotusedVoice!=NULL)&&(LastnotusedVoice->id==FirstVoice->id)) + { +#ifdef VOICEMANDEBUG + printf("Used last voice !\n"); +#endif + LastnotusedVoice=NULL; + } + voice *newvoice=FirstVoice; + FirstVoice=FirstVoice->next; + FirstVoice->prev=NULL; + +#ifdef VOICEMANDEBUG + printf("Allocating id :%d\n",newvoice->id); +#endif + // then we put the allocated voice at the end of the list + LastVoice->next=newvoice; + newvoice->prev=LastVoice; + LastVoice=newvoice; + LastVoice->next=NULL; + + newvoice->channel=chn; + newvoice->note=key; + +#ifdef VOICEMANDEBUG + if (newvoice->used==1) + { + printf("Replacing voice : %d\n",newvoice->id); + } +#endif + newvoice->used=1; + + //dispStat(); + return newvoice->id; +} + +void VoiceManager::deallocateVoice(int id) +{ + voice *delvoice=VoiceList[id]; +#ifdef VOICEMANDEBUG + printf("Deallocating id :%d\n",id); +#endif + if (delvoice->id==LastVoice->id) + { + LastVoice=delvoice->prev; + LastVoice->next=NULL; + + if (LastnotusedVoice==NULL) + { + delvoice->next=FirstVoice; + FirstVoice->prev=delvoice; + FirstVoice=delvoice; + FirstVoice->prev=NULL; + LastnotusedVoice=FirstVoice; + } + else + { + if (LastnotusedVoice->next==NULL) + { + LastnotusedVoice->next=delvoice; + delvoice->prev=LastnotusedVoice; + delvoice->next=NULL; + LastnotusedVoice=delvoice; + LastVoice=delvoice; + } + else + { + delvoice->next=LastnotusedVoice->next; + delvoice->next->prev=delvoice; + delvoice->prev=LastnotusedVoice; + LastnotusedVoice->next=delvoice; + LastnotusedVoice=delvoice; + } + } + } + else + { + if (delvoice->prev!=NULL) + { + delvoice->prev->next=delvoice->next; + delvoice->next->prev=delvoice->prev; + if (LastnotusedVoice==NULL) + { + delvoice->next=FirstVoice; + FirstVoice->prev=delvoice; + FirstVoice=delvoice; + FirstVoice->prev=NULL; + LastnotusedVoice=FirstVoice; } + else + { + if (LastnotusedVoice->next==NULL) + { + LastnotusedVoice->next=delvoice; + delvoice->prev=LastnotusedVoice; + delvoice->next=NULL; + LastnotusedVoice=delvoice; + LastVoice=delvoice; + } + else + { + delvoice->next=LastnotusedVoice->next; + delvoice->next->prev=delvoice; + delvoice->prev=LastnotusedVoice; + LastnotusedVoice->next=delvoice; + LastnotusedVoice=delvoice; + } + } + } + } + delvoice->used=0; + + // dispStat(); +} + +void VoiceManager::initSearch(void) +{ + searcher=searcher_aid; + searcher_aid->prev=LastVoice; +} + +int VoiceManager::search(int chn) +{ + if (searcher==NULL) return -1; + searcher=searcher->prev; + + while (searcher!=NULL) + { + if (searcher->used==0) return -1; + if (searcher->channel==chn) + { + return searcher->id; + } + searcher=searcher->prev; + } + return -1; +} + +int VoiceManager::search(int chn,int note) +{ + if (searcher==NULL) return -1; + searcher=searcher->prev; + while ((searcher!=NULL)) + { + if (searcher->used==0) return -1; + if ((searcher->channel==chn)&&(searcher->note==note)) + { + return searcher->id; + } + searcher=searcher->prev; + } + return -1; +} + +/* +void VoiceManager::dispStat(void) +{ +#ifdef VOICEMANDEBUG + printf("Stats\n"); + voice *ptr=FirstVoice; + while (ptr!=NULL) + { + printf("Voice %d is %s\n",ptr->id,(ptr->used==0)?("off"):("on")); + ptr=ptr->next; + } + if (LastnotusedVoice!=NULL) printf("LnuV = %d\n",LastnotusedVoice->id); +#endif +} +*/ -- cgit v1.2.1