From 9498962e76d4c1757af6d03eb0ee187821090281 Mon Sep 17 00:00:00 2001 From: Werner Schweer Date: Wed, 25 Jun 2008 17:43:56 +0000 Subject: cleanups --- muse/muse/CMakeLists.txt | 3 +- muse/muse/audiodev.h | 56 +++ muse/muse/driver.h | 64 +++ muse/muse/driver/CMakeLists.txt | 20 - muse/muse/driver/audiodev.h | 56 --- muse/muse/driver/driver.h | 64 --- muse/muse/driver/dummyaudio.cpp | 294 ------------- muse/muse/driver/jack.cpp | 931 ---------------------------------------- muse/muse/driver/jackaudio.h | 87 ---- muse/muse/driver/port.h | 76 ---- muse/muse/dummyaudio.cpp | 294 +++++++++++++ muse/muse/jack.cpp | 931 ++++++++++++++++++++++++++++++++++++++++ muse/muse/jackaudio.h | 87 ++++ muse/muse/port.h | 76 ++++ 14 files changed, 1509 insertions(+), 1530 deletions(-) create mode 100644 muse/muse/audiodev.h create mode 100644 muse/muse/driver.h delete mode 100644 muse/muse/driver/CMakeLists.txt delete mode 100644 muse/muse/driver/audiodev.h delete mode 100644 muse/muse/driver/driver.h delete mode 100644 muse/muse/driver/dummyaudio.cpp delete mode 100644 muse/muse/driver/jack.cpp delete mode 100644 muse/muse/driver/jackaudio.h delete mode 100644 muse/muse/driver/port.h create mode 100644 muse/muse/dummyaudio.cpp create mode 100644 muse/muse/jack.cpp create mode 100644 muse/muse/jackaudio.h create mode 100644 muse/muse/port.h diff --git a/muse/muse/CMakeLists.txt b/muse/muse/CMakeLists.txt index 68eeddaf..1bda0e5c 100644 --- a/muse/muse/CMakeLists.txt +++ b/muse/muse/CMakeLists.txt @@ -29,7 +29,6 @@ subdirs ( midiedit widgets master - driver instruments marker liste @@ -159,6 +158,7 @@ add_executable ( muse audiogroup.cpp exportmidi.cpp revision.cpp + jack.cpp dummyaudio.cpp ) set_target_properties( muse @@ -168,7 +168,6 @@ set_target_properties( muse target_link_libraries(muse midiedit master - driver instruments marker liste diff --git a/muse/muse/audiodev.h b/muse/muse/audiodev.h new file mode 100644 index 00000000..55830c14 --- /dev/null +++ b/muse/muse/audiodev.h @@ -0,0 +1,56 @@ +//============================================================================= +// MusE +// Linux Music Editor +// $Id:$ +// +// Copyright (C) 2002-2006 by Werner Schweer and others +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2. +// +// This program 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 General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +//============================================================================= + +#ifndef __AUDIODEV_H__ +#define __AUDIODEV_H__ + +#include "driver.h" + +//--------------------------------------------------------- +// AudioDevice +//--------------------------------------------------------- + +class AudioDriver : public Driver { + + public: + AudioDriver() {} + virtual ~AudioDriver() {} + + virtual void start(int priority) = 0; + virtual bool restart() { return false; } // return true on error + virtual void stop () = 0; + virtual unsigned curFrame() const = 0; + virtual unsigned frameTime() const = 0; + virtual unsigned lastFrameTime() const = 0; + virtual float* getBuffer(Port, unsigned long nframes) = 0; + virtual void registerClient() = 0; + virtual Port registerOutPort(const QString& name, bool midi) = 0; + virtual Port registerInPort(const QString& name, bool midi) = 0; + virtual int realtimePriority() const = 0; // return zero if not realtime + virtual void startTransport() = 0; + virtual void stopTransport() = 0; + virtual void seekTransport(unsigned frame) = 0; + virtual void setFreewheel(bool f) = 0; + virtual void graphChanged() {} + virtual void startMidiCycle(Port) {} + }; + +#endif + diff --git a/muse/muse/driver.h b/muse/muse/driver.h new file mode 100644 index 00000000..c8bbfc7f --- /dev/null +++ b/muse/muse/driver.h @@ -0,0 +1,64 @@ +//============================================================================= +// MusE +// Linux Music Editor +// $Id:$ +// +// Copyright (C) 2002-2006 by Werner Schweer and others +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2. +// +// This program 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 General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +//============================================================================= + +#ifndef __DRIVER_H__ +#define __DRIVER_H__ + +#include +#include "port.h" + +struct PortName { + Port port; + QString name; + }; + +class MidiEvent; + +//--------------------------------------------------------- +// Driver +// abstract driver base class; used for midi and +// audio +//--------------------------------------------------------- + +class Driver { + + public: + Driver() {} + virtual ~Driver() {} + virtual bool init() = 0; + + virtual QList outputPorts(bool midi) = 0; + virtual QList inputPorts(bool midi) = 0; + + virtual Port registerOutPort(const QString&, bool midi) = 0; + virtual Port registerInPort(const QString&, bool midi) = 0; + virtual void unregisterPort(Port) = 0; + virtual void setPortName(Port p, const QString&) = 0; + virtual QString portName(Port) = 0; + virtual Port findPort(const QString&) = 0; + + virtual bool connect(Port, Port) = 0; + virtual bool disconnect(Port, Port) = 0; + virtual void putEvent(Port, const MidiEvent&) = 0; + virtual void updateConnections() {} + }; + +#endif + diff --git a/muse/muse/driver/CMakeLists.txt b/muse/muse/driver/CMakeLists.txt deleted file mode 100644 index 80612301..00000000 --- a/muse/muse/driver/CMakeLists.txt +++ /dev/null @@ -1,20 +0,0 @@ -# -# -# -# - -IF (APPLE) -set ( driver_src - jack.cpp dummyaudio.cpp coretimer.cpp coremidi.cpp - ) -ELSE (APPLE) -set ( driver_src - jack.cpp dummyaudio.cpp - ) -ENDIF (APPLE) - -add_library ( driver STATIC ${driver_src} ) -set_target_properties( driver - PROPERTIES COMPILE_FLAGS "-include ${PROJECT_BINARY_DIR}/all.h" - ) - diff --git a/muse/muse/driver/audiodev.h b/muse/muse/driver/audiodev.h deleted file mode 100644 index 55830c14..00000000 --- a/muse/muse/driver/audiodev.h +++ /dev/null @@ -1,56 +0,0 @@ -//============================================================================= -// MusE -// Linux Music Editor -// $Id:$ -// -// Copyright (C) 2002-2006 by Werner Schweer and others -// -// This program is free software; you can redistribute it and/or modify -// it under the terms of the GNU General Public License version 2. -// -// This program 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 General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program; if not, write to the Free Software -// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -//============================================================================= - -#ifndef __AUDIODEV_H__ -#define __AUDIODEV_H__ - -#include "driver.h" - -//--------------------------------------------------------- -// AudioDevice -//--------------------------------------------------------- - -class AudioDriver : public Driver { - - public: - AudioDriver() {} - virtual ~AudioDriver() {} - - virtual void start(int priority) = 0; - virtual bool restart() { return false; } // return true on error - virtual void stop () = 0; - virtual unsigned curFrame() const = 0; - virtual unsigned frameTime() const = 0; - virtual unsigned lastFrameTime() const = 0; - virtual float* getBuffer(Port, unsigned long nframes) = 0; - virtual void registerClient() = 0; - virtual Port registerOutPort(const QString& name, bool midi) = 0; - virtual Port registerInPort(const QString& name, bool midi) = 0; - virtual int realtimePriority() const = 0; // return zero if not realtime - virtual void startTransport() = 0; - virtual void stopTransport() = 0; - virtual void seekTransport(unsigned frame) = 0; - virtual void setFreewheel(bool f) = 0; - virtual void graphChanged() {} - virtual void startMidiCycle(Port) {} - }; - -#endif - diff --git a/muse/muse/driver/driver.h b/muse/muse/driver/driver.h deleted file mode 100644 index c8bbfc7f..00000000 --- a/muse/muse/driver/driver.h +++ /dev/null @@ -1,64 +0,0 @@ -//============================================================================= -// MusE -// Linux Music Editor -// $Id:$ -// -// Copyright (C) 2002-2006 by Werner Schweer and others -// -// This program is free software; you can redistribute it and/or modify -// it under the terms of the GNU General Public License version 2. -// -// This program 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 General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program; if not, write to the Free Software -// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -//============================================================================= - -#ifndef __DRIVER_H__ -#define __DRIVER_H__ - -#include -#include "port.h" - -struct PortName { - Port port; - QString name; - }; - -class MidiEvent; - -//--------------------------------------------------------- -// Driver -// abstract driver base class; used for midi and -// audio -//--------------------------------------------------------- - -class Driver { - - public: - Driver() {} - virtual ~Driver() {} - virtual bool init() = 0; - - virtual QList outputPorts(bool midi) = 0; - virtual QList inputPorts(bool midi) = 0; - - virtual Port registerOutPort(const QString&, bool midi) = 0; - virtual Port registerInPort(const QString&, bool midi) = 0; - virtual void unregisterPort(Port) = 0; - virtual void setPortName(Port p, const QString&) = 0; - virtual QString portName(Port) = 0; - virtual Port findPort(const QString&) = 0; - - virtual bool connect(Port, Port) = 0; - virtual bool disconnect(Port, Port) = 0; - virtual void putEvent(Port, const MidiEvent&) = 0; - virtual void updateConnections() {} - }; - -#endif - diff --git a/muse/muse/driver/dummyaudio.cpp b/muse/muse/driver/dummyaudio.cpp deleted file mode 100644 index b4bc73ff..00000000 --- a/muse/muse/driver/dummyaudio.cpp +++ /dev/null @@ -1,294 +0,0 @@ -//============================================================================= -// MusE -// Linux Music Editor -// $Id:$ -// -// Copyright (C) 2002-2006 by Werner Schweer and others -// -// This program is free software; you can redistribute it and/or modify -// it under the terms of the GNU General Public License version 2. -// -// This program 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 General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program; if not, write to the Free Software -// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -//============================================================================= - -#include "al/al.h" -#include "widgets/utils.h" -#include "audio.h" -#include "audiodev.h" -#include "globals.h" -#include "song.h" - -static const unsigned dummyFrames = 1024; -static double startTime; - -//--------------------------------------------------------- -// DummyAudio -//--------------------------------------------------------- - -class DummyAudio : public AudioDriver { - float* buffer; - pthread_t dummyThread; - std::vector oPorts; - std::vector iPorts; - int realTimePriority; - - public: - int state; - bool seekflag; - unsigned pos; - - DummyAudio() { - state = Audio::STOP; - seekflag = false; - startTime = curTime(); - posix_memalign((void**)&buffer, 16, sizeof(float) * dummyFrames); - } - virtual ~DummyAudio() { - free(buffer); - } - - virtual bool init() { return true; } - virtual void start(int); - virtual void stop (); - virtual unsigned frameTime() const { - return lrint(curTime() * AL::sampleRate); - } - virtual unsigned lastFrameTime() const { - return lrint(startTime * AL::sampleRate); - } - virtual unsigned curFrame() const { return pos; } - - virtual float* getBuffer(Port /*port*/, unsigned long nframes) - { - if (nframes > dummyFrames) { - fprintf(stderr, "error: segment size > %d\n", dummyFrames); - exit(-1); - } - memset(buffer, 0, nframes * sizeof(float)); - return buffer; - } - - virtual QList outputPorts(bool midi = false); - virtual QList inputPorts(bool midi = false); - - virtual void registerClient() {} - - virtual Port registerOutPort(const QString& s, bool) { - iPorts.push_back(QString(s)); - Port port(0, iPorts.size() + 3000); - return port; - } - virtual Port registerInPort(const QString& s, bool) { - oPorts.push_back(QString(s)); - Port port(0, oPorts.size() + 40); - return port; - } - virtual void unregisterPort(Port) { -/* if (long(p) >= 100) - oPorts.erase(oPorts.begin() + (long(p)-40)); - else - iPorts.erase(iPorts.begin() + long(p)-30); -*/ - } - virtual bool connect(Port, Port) { return true; } - virtual bool disconnect(Port, Port) { return true; } - virtual void setPortName(Port, const QString&) {} - virtual Port findPort(const QString& s) { - if (s == "input1") - return Port(0, 10); - if (s == "input2") - return Port(0, 11); - if (s == "output1") - return Port(0, 20); - if (s == "output2") - return Port(0, 21); - int k = 0; - for (std::vector::const_iterator i = iPorts.begin(); i != iPorts.end(); ++i, ++k) { - if (s == *i) - return Port(0, 30+k); - } - k = 0; - for (std::vector::const_iterator i = oPorts.begin(); i != oPorts.end(); ++i, ++k) { - if (s == *i) - return Port(0, 40); - } - return Port(); - } - virtual QString portName(Port port) { - if (port.alsaPort() == 10) - return QString("input1"); - if (port.alsaPort() == 11) - return QString("input2"); - if (port.alsaPort() == 20) - return QString("output1"); - if (port.alsaPort() == 21) - return QString("output2"); - if (port.alsaPort() >= 40) - return QString(oPorts[port.alsaPort() - 40]); - else - return QString(iPorts[port.alsaPort() - 30]); - } - virtual int realtimePriority() const { return 40; } - virtual void startTransport() { - state = Audio::PLAY; - } - virtual void stopTransport() { - state = Audio::STOP; - } - virtual void seekTransport(unsigned n) { - seekflag = true; - pos = n; - } - virtual void setFreewheel(bool) {} - virtual void putEvent(Port, const MidiEvent&) {} - }; - -DummyAudio* dummyAudio; - -//--------------------------------------------------------- -// initDummyAudio -//--------------------------------------------------------- - -bool initDummyAudio() - { - dummyAudio = new DummyAudio(); - audioDriver = dummyAudio; - return false; - } - -//--------------------------------------------------------- -// outputPorts -//--------------------------------------------------------- - -QList DummyAudio::outputPorts(bool midi) - { - QList clientList; - if (!midi) { - PortName p1; - p1.name = QString("output1"); - p1.port = Port(0, 100); - PortName p2; - p2.name = QString("output2"); - p2.port = Port(0, 101); - clientList.append(p1); - clientList.append(p2); - } - return clientList; - } - -//--------------------------------------------------------- -// inputPorts -//--------------------------------------------------------- - -QList DummyAudio::inputPorts(bool midi) - { - QList clientList; - if (!midi) { - PortName p1; - p1.name = QString("input1"); - p1.port = Port(0, 0); - PortName p2; - p2.name = QString("input2"); - p2.port = Port(0, 1); - clientList.append(p1); - clientList.append(p2); - } - return clientList; - } - -//--------------------------------------------------------- -// dummyLoop -//--------------------------------------------------------- - -static void* dummyLoop(void*) - { -#ifndef __APPLE__ - if (realTimePriority) { - // - // check if we really got realtime priviledges - // - int policy; - if ((policy = sched_getscheduler (0)) < 0) { - printf("cannot get current client scheduler for audio dummy thread: %s!\n", strerror(errno)); - } - else - { - if (policy != SCHED_FIFO) - printf("audio dummy thread _NOT_ running SCHED_FIFO\n"); - else if (debugMsg) { - struct sched_param rt_param; - memset(&rt_param, 0, sizeof(sched_param)); - int type; - int rv = pthread_getschedparam(pthread_self(), &type, &rt_param); - if (rv == -1) - perror("get scheduler parameter"); - printf("audio dummy thread running SCHED_FIFO priority %d\n", - rt_param.sched_priority); - } - } - } -#endif - - for (;;) { - if (audioState == AUDIO_RUNNING) - audio->process(segmentSize, dummyAudio->state); - else if (audioState == AUDIO_START1) - audioState = AUDIO_START2; - usleep(dummyFrames*1000000/AL::sampleRate); - if (dummyAudio->seekflag) { - audio->sync(Audio::STOP, dummyAudio->pos); - dummyAudio->seekflag = false; - } - if (dummyAudio->state == Audio::PLAY) { - dummyAudio->pos += dummyFrames; - } - } - pthread_exit(0); - } - -//--------------------------------------------------------- -// start -//--------------------------------------------------------- - -void DummyAudio::start(int priority) - { - realTimePriority = priority; - pthread_attr_t* attributes = 0; - - if (priority) { - attributes = (pthread_attr_t*) malloc(sizeof(pthread_attr_t)); - pthread_attr_init(attributes); - - if (pthread_attr_setschedpolicy(attributes, SCHED_FIFO)) { - printf("cannot set FIFO scheduling class for RT thread\n"); - } - if (pthread_attr_setscope (attributes, PTHREAD_SCOPE_SYSTEM)) { - printf("Cannot set scheduling scope for RT thread\n"); - } - struct sched_param rt_param; - memset(&rt_param, 0, sizeof(rt_param)); - rt_param.sched_priority = priority; - if (pthread_attr_setschedparam (attributes, &rt_param)) { - printf("Cannot set scheduling priority %d for RT thread (%s)\n", - priority, strerror(errno)); - } - } - if (pthread_create(&dummyThread, attributes, ::dummyLoop, this)) - perror("creating thread failed:"); - if (priority) - pthread_attr_destroy(attributes); - } - -void DummyAudio::stop () - { - pthread_cancel(dummyThread); - pthread_join(dummyThread, 0); - } - diff --git a/muse/muse/driver/jack.cpp b/muse/muse/driver/jack.cpp deleted file mode 100644 index cde57418..00000000 --- a/muse/muse/driver/jack.cpp +++ /dev/null @@ -1,931 +0,0 @@ -//============================================================================= -// MusE -// Linux Music Editor -// $Id:$ -// -// Copyright (C) 2002-2006 by Werner Schweer and others -// -// This program is free software; you can redistribute it and/or modify -// it under the terms of the GNU General Public License version 2. -// -// This program 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 General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program; if not, write to the Free Software -// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -//============================================================================= - -#include "config.h" -#include "al/al.h" -#include "al/tempo.h" -#include "audio.h" -#include "globals.h" -#include "song.h" -#include "jackaudio.h" -#include "track.h" - -#ifdef VST_SUPPORT -#include -#endif - -JackAudio* jackAudio; - -//--------------------------------------------------------- -// init -//--------------------------------------------------------- - -bool JackAudio::init() - { - return true; - } - -//--------------------------------------------------------- -// jack_thread_init -//--------------------------------------------------------- - -static void jack_thread_init (void* /*data*/) - { -#ifdef VST_SUPPORT - if (loadVST) - fst_adopt_thread(); -#endif - int policy; - if ( (policy = sched_getscheduler (0)) < 0) { - printf("cannot get current client scheduler for JACK thread: %s!\n", strerror(errno)); - } - else { - if (policy != SCHED_FIFO) - printf("JACK thread %d _NOT_ running SCHED_FIFO\n", getpid()); - else if (debugMsg) { - struct sched_param rt_param; - memset(&rt_param, 0, sizeof(sched_param)); - int type; - int rv = pthread_getschedparam(pthread_self(), &type, &rt_param); - if (rv == -1) - perror("get scheduler parameter"); - printf("JACK thread running SCHED_FIFO priority %d\n", - rt_param.sched_priority); - } - } - - } - -//--------------------------------------------------------- -// timebase_callback -//--------------------------------------------------------- - -static void timebase_callback(jack_transport_state_t /* state */, - jack_nframes_t /* nframes */, - jack_position_t* pos, - int /* new_pos */, - void*) - { - AL::Pos p(pos->frame, AL::FRAMES); - pos->valid = JackPositionBBT; - p.mbt(&pos->bar, &pos->beat, &pos->tick); - pos->bar++; - pos->beat++; - pos->bar_start_tick = Pos(pos->bar, 0, 0).tick(); - // - // dummy: - // - pos->beats_per_bar = 4; - pos->beat_type = 4; - pos->ticks_per_beat = 384; - int tempo = AL::tempomap.tempo(p.tick()); - pos->beats_per_minute = (60000000.0 / tempo) * AL::tempomap.globalTempo()/100.0; - } - -//--------------------------------------------------------- -// processAudio -// JACK callback -//--------------------------------------------------------- - -static int processAudio(jack_nframes_t frames, void*) - { -#if 0 - unsigned t1 = jackAudio->frameTime(); - unsigned t2 = jackAudio->lastFrameTime(); - unsigned t3 = jackAudio->framesSinceCyleStart(); - unsigned t4 = jackAudio->getCurFrame(); - -printf("cycle %8d %8d %8d %08d\n", t1, t2, t3, t4); -#endif - - int jackState = jackAudio->getTransportState(); - segmentSize = frames; - if (audioState == AUDIO_RUNNING) - audio->process((unsigned long)frames, jackState); - else if (audioState == AUDIO_STOP) { - if (debugMsg) - puts("jack calling when audio is stopped!\n"); - } - else if (audioState == AUDIO_START1) - audioState = AUDIO_START2; - return 0; - } - -//--------------------------------------------------------- -// getTransportState -//--------------------------------------------------------- - -int JackAudio::getTransportState() - { - int jackState; - transportState = jack_transport_query(_client, &pos); - switch (jackAudio->transportState) { - case JackTransportStopped: - jackState = Audio::STOP; - break; - case JackTransportLooping: - case JackTransportRolling: - jackState = Audio::PLAY; - break; - case JackTransportStarting: - jackState = Audio::START_PLAY; - break; - default: - jackState = Audio::STOP; - break; - } - return jackState; - } - -//--------------------------------------------------------- -// processSync -// return TRUE (non-zero) when ready to roll. -//--------------------------------------------------------- - -static int processSync(jack_transport_state_t state, jack_position_t* pos, void*) - { - int audioState = Audio::STOP; - switch (state) { - case JackTransportStopped: - audioState = Audio::STOP; - break; - case JackTransportLooping: - case JackTransportRolling: - audioState = Audio::PLAY; - break; - case JackTransportStarting: - audioState = Audio::START_PLAY; - break; - } - unsigned frame = pos->frame; - return audio->sync(audioState, frame); - } - -//--------------------------------------------------------- -// processShutdown -//--------------------------------------------------------- - -static void processShutdown(void*) - { - audio->shutdown(); - - for (int i = 0; i < 10; ++i) { - if (audioState == AUDIO_STOP) - break; - sleep(1); - } - if (audioState == AUDIO_RUNNING) - fprintf(stderr, "MusE: sequencer still running, something is very wrong.\n"); - jackAudio->zeroClientPtr(); // jack disconnect client no longer valid - } - -//--------------------------------------------------------- -// jackError -//--------------------------------------------------------- - -static void jackError(const char* s) - { - fprintf(stderr, "JACK ERROR: %s\n", s); - } - -//--------------------------------------------------------- -// noJackError -//--------------------------------------------------------- - -static void noJackError(const char* /* s */) - { - } - -//--------------------------------------------------------- -// JackAudio -//--------------------------------------------------------- - -JackAudio::JackAudio(jack_client_t* cl, char* name) - : AudioDriver() - { - strcpy(jackRegisteredName, name); - _client = cl; - } - -//--------------------------------------------------------- -// ~JackAudio -//--------------------------------------------------------- - -JackAudio::~JackAudio() - { - if (_client) { - if (jack_client_close(_client)) { - fprintf(stderr, "jack_client_close() failed: %s\n", - strerror(errno)); - } - } - _client = 0; - } - -//--------------------------------------------------------- -// getJackName() -//--------------------------------------------------------- - -char* JackAudio::getJackName() - { - return jackRegisteredName; - } - -//--------------------------------------------------------- -// restart -//--------------------------------------------------------- - -bool JackAudio::restart() - { - printf("JackAudio::restart\n"); - _client = jack_client_new(jackRegisteredName); - if (!_client) - return true; - registerClient(); - return false; - } - -//--------------------------------------------------------- -// bufsize_callback -//--------------------------------------------------------- - -static int bufsize_callback(jack_nframes_t n, void*) - { - printf("JACK: buffersize changed %d\n", n); - return 0; - } - -//--------------------------------------------------------- -// freewheel_callback -//--------------------------------------------------------- - -static void freewheel_callback(int starting, void*) - { - audio->setFreewheel(starting); - } - -//--------------------------------------------------------- -// srate_callback -//--------------------------------------------------------- - -static int srate_callback(jack_nframes_t n, void*) - { - if (debugMsg) - printf("JACK: sample rate changed: %d\n", n); - return 0; - } - -//--------------------------------------------------------- -// registration_callback -//--------------------------------------------------------- - -static void registration_callback(jack_port_id_t, int, void*) - { - if (debugMsg) - printf("JACK: registration changed\n"); - } - -//--------------------------------------------------------- -// graph_callback -// this is called from jack when the connections -// changed -//--------------------------------------------------------- - -static int graph_callback(void*) - { - // we cannot call JackAudio::graphChanged() from this - // context, so we send a message to the gui thread which in turn - // calls graphChanged() - - audio->sendMsgToGui(MSG_GRAPH_CHANGED); - if (debugMsg) - printf("JACK: graph changed!\n"); - return 0; - } - -//--------------------------------------------------------- -// JackAudio::graphChanged -// this is called from song in gui context triggered -// by graph_callback() -//--------------------------------------------------------- - -void JackAudio::graphChanged() - { - RouteList rr, ra; - - InputList* il = song->inputs(); - for (iAudioInput ii = il->begin(); ii != il->end(); ++ii) { - AudioInput* it = *ii; - int channels = it->channels(); - RouteList* irl = it->inRoutes(); - - for (int channel = 0; channel < channels; ++channel) { - jack_port_t* port = it->jackPort(channel).jackPort(); - if (port == 0) - continue; - const char** ports = jack_port_get_all_connections(_client, port); - - //--------------------------------------- - // check for disconnects - //--------------------------------------- - - foreach (const Route& r, *irl) { - if (r.dst.channel != channel) - continue; - const char* name = jack_port_name(r.src.port.jackPort()); - bool found = false; - for (const char** pn = ports; pn && *pn; ++pn) { - if (strcmp(*pn, name) == 0) { - found = true; - break; - } - } - if (!found) - rr.append(r); - } - - //--------------------------------------- - // check for connects - //--------------------------------------- - - if (ports) { - for (const char** pn = ports; *pn; ++pn) { - bool found = false; - foreach(const Route& r, *irl) { - if (r.dst.channel != channel) - continue; - const char* name = jack_port_name(r.src.port.jackPort()); - if (strcmp(*pn, name) == 0) { - found = true; - break; - } - } - if (!found) { - Route a; - Port port(jack_port_by_name(_client, *pn)); - a.src = RouteNode(port, -1, RouteNode::AUDIOPORT); - a.dst = RouteNode(it, channel); - ra.append(a); - } - } - free(ports); - } - } - } - -// printf(" input: remove %d add %d routes\n", rr.size(), ra.size()); - foreach(Route r, rr) - audio->msgRemoveRoute1(r); - foreach(Route r, ra) - audio->msgAddRoute1(r); - rr.clear(); - ra.clear(); - - OutputList* ol = song->outputs(); - for (iAudioOutput ii = ol->begin(); ii != ol->end(); ++ii) { - AudioOutput* it = *ii; - int channels = it->channels(); - for (int channel = 0; channel < channels; ++channel) { - jack_port_t* port = it->jackPort(channel).jackPort(); - if (port == 0) - continue; - const char** ports = jack_port_get_all_connections(_client, port); - RouteList* rl = it->outRoutes(); - - //--------------------------------------- - // check for disconnects - //--------------------------------------- - - foreach(const Route& r, *rl) { - if (r.src.channel != channel) - continue; - const char* name = jack_port_name(r.dst.port.jackPort()); - bool found = false; - const char** pn = ports; - while (pn && *pn) { - if (strcmp(*pn, name) == 0) { - found = true; - break; - } - ++pn; - } - if (!found) - rr.append(r); - } - - //--------------------------------------- - // check for connects - //--------------------------------------- - - if (ports) { - const char** pn = ports; - while (*pn) { - bool found = false; - foreach (const Route& r, *rl) { - if (r.src.channel != channel) - continue; - const char* name = jack_port_name(r.dst.port.jackPort()); - if (strcmp(*pn, name) == 0) { - found = true; - break; - } - } - if (!found) { - Route a; - Port port(jack_port_by_name(_client, *pn)); - a.src = RouteNode(it, channel, RouteNode::TRACK); - a.dst = RouteNode(port, -1, RouteNode::AUDIOPORT); - ra.append(a); - } - ++pn; - } - free(ports); - } - } - } -// printf(" output: remove %d add %d routes\n", rr.size(), ra.size()); - foreach(Route r, rr) - audio->msgRemoveRoute1(r); - foreach(Route r, ra) - audio->msgAddRoute1(r); - } - -//static int xrun_callback(void*) -// { -// printf("JACK: xrun\n"); -// return 0; -// } - -//--------------------------------------------------------- -// register -//--------------------------------------------------------- - -void JackAudio::registerClient() - { - jack_set_process_callback(_client, processAudio, 0); - jack_set_sync_callback(_client, processSync, 0); - jack_on_shutdown(_client, processShutdown, 0); - jack_set_buffer_size_callback(_client, bufsize_callback, 0); - jack_set_sample_rate_callback(_client, srate_callback, 0); - jack_set_port_registration_callback(_client, registration_callback, 0); - jack_set_graph_order_callback(_client, graph_callback, 0); -// jack_set_xrun_callback(_client, xrun_callback, 0); - jack_set_freewheel_callback (_client, freewheel_callback, 0); - jack_set_thread_init_callback(_client, (JackThreadInitCallback) jack_thread_init, 0); - jack_set_timebase_callback(_client, 0, timebase_callback, 0); - } - -//--------------------------------------------------------- -// registerInPort -//--------------------------------------------------------- - -Port JackAudio::registerInPort(const QString& name, bool midi) - { - const char* type = midi ? JACK_DEFAULT_MIDI_TYPE : JACK_DEFAULT_AUDIO_TYPE; - Port p(jack_port_register(_client, name.toLatin1().data(), type, JackPortIsInput, 0)); -// printf("JACK: registerInPort<%s>: <%s> %p\n", type, name.toLatin1().data(), p.jackPort()); - if (!p.jackPort()) - p.setZero(); - return p; - } - -//--------------------------------------------------------- -// registerOutPort -//--------------------------------------------------------- - -Port JackAudio::registerOutPort(const QString& name, bool midi) - { - const char* type = midi ? JACK_DEFAULT_MIDI_TYPE : JACK_DEFAULT_AUDIO_TYPE; - Port p(jack_port_register(_client, name.toLatin1().data(), type, JackPortIsOutput, 0)); -// printf("JACK: registerOutPort<%s>: <%s> %p\n", type, name.toLatin1().data(), p.jackPort()); -#if 0 - if (midi) { - jack_nframes_t nframes = jack_get_buffer_size(_client); - jack_midi_reset_new_port(jack_port_get_buffer(p.jackPort(), nframes), nframes); - } -#endif - if (!p.jackPort()) - p.setZero(); - return p; - } - -//--------------------------------------------------------- -// exitJackAudio -//--------------------------------------------------------- - -void exitJackAudio() - { - if (jackAudio) - delete jackAudio; - } - -//--------------------------------------------------------- -// connect -// return false on error -//--------------------------------------------------------- - -bool JackAudio::connect(Port src, Port dst) - { - if (src.isZero() || dst.isZero()) { - fprintf(stderr, "JackAudio::connect(1): unknown jack ports (%d-%d)\n", - src.isZero(), dst.isZero()); - return false; - } - const char* sn = jack_port_name(src.jackPort()); - const char* dn = jack_port_name(dst.jackPort()); - - if (debugMsg) - printf("jack connect <%s>%p - <%s>%p\n", sn, src.jackPort(), dn, dst.jackPort()); - - if (sn == 0 || dn == 0) { - fprintf(stderr, "JackAudio::connect(2): unknown jack ports\n"); - return false; - } - int rv = jack_connect(_client, sn, dn); - if (rv) { - fprintf(stderr, "%d: jack connect <%s> - <%s> failed\n", - rv, sn, dn); - if (rv == EEXIST) - fprintf(stderr, " connection already made\n"); - else { - int pf = jack_port_flags(src.jackPort()); - if (!(pf & JackPortIsOutput)) - fprintf(stderr, " src is not an output port\n"); - pf = jack_port_flags(dst.jackPort()); - if (!(pf & JackPortIsInput)) - fprintf(stderr, " dst is not an input port\n"); - } - return false; - } - return true; - } - -//--------------------------------------------------------- -// disconnect -//--------------------------------------------------------- - -bool JackAudio::disconnect(Port src, Port dst) - { - const char* sn = jack_port_name(src.jackPort()); - const char* dn = jack_port_name(dst.jackPort()); - - if (debugMsg) - printf("jack disconnect <%s>%p - <%s>%p\n", sn, src.jackPort(), dn, dst.jackPort()); - - if (sn == 0 || dn == 0) { - fprintf(stderr, "JackAudio::disconnect: unknown jack ports\n"); - return false; - } - if (jack_disconnect(_client, sn, dn)) { - fprintf(stderr, "jack disconnect <%s> - <%s> failed\n", - sn, dn); - return false; - } - return true; - } - -//--------------------------------------------------------- -// start -//--------------------------------------------------------- - -void JackAudio::start(int) - { - if (jack_activate(_client)) { - fprintf (stderr, "JACK: cannot activate client\n"); - exit(-1); - } - } - -//--------------------------------------------------------- -// stop -//--------------------------------------------------------- - -void JackAudio::stop() - { - if (_client == 0) - return; - if (jack_deactivate(_client)) - fprintf (stderr, "JACK: cannot deactivate client\n"); - } - -//--------------------------------------------------------- -// outputPorts -//--------------------------------------------------------- - -QList JackAudio::outputPorts(bool midi) - { - const char* type = midi ? JACK_DEFAULT_MIDI_TYPE : JACK_DEFAULT_AUDIO_TYPE; - const char** ports = jack_get_ports(_client, 0, type, JackPortIsOutput); - QList clientList; - for (const char** p = ports; p && *p; ++p) { - jack_port_t* port = jack_port_by_name(_client, *p); - char buffer[128]; - strncpy(buffer, *p, 128); - if (strncmp(buffer, "MusE", 4) == 0) - continue; - PortName pn; - pn.name = QString(buffer); - pn.port = Port(port); - clientList.append(pn); - } - return clientList; - } - -//--------------------------------------------------------- -// inputPorts -//--------------------------------------------------------- - -QList JackAudio::inputPorts(bool midi) - { - const char* type = midi ? JACK_DEFAULT_MIDI_TYPE : JACK_DEFAULT_AUDIO_TYPE; - const char** ports = jack_get_ports(_client, 0, type, JackPortIsInput); - QList clientList; - for (const char** p = ports; p && *p; ++p) { - jack_port_t* port = jack_port_by_name(_client, *p); - char buffer[128]; - strncpy(buffer, *p, 128); - if (strncmp(buffer, "MusE", 4) == 0) - continue; - PortName pn; - pn.name = QString(buffer); - pn.port = Port(port); - clientList.append(pn); - } - return clientList; - } - -//--------------------------------------------------------- -// portName -//--------------------------------------------------------- - -QString JackAudio::portName(Port port) - { - const char* nameStrPtr = jack_port_name(port.jackPort()); - QString s(nameStrPtr); - return s; - } - -//--------------------------------------------------------- -// unregisterPort -//--------------------------------------------------------- - -void JackAudio::unregisterPort(Port p) - { - if (_client) { -// printf("JACK: unregister Port %p\n", p); - if (jack_port_unregister(_client, p.jackPort())) - fprintf(stderr, "jack unregister port %p failed\n", p.jackPort()); - } - } - -//--------------------------------------------------------- -// setFreewheel -//--------------------------------------------------------- - -void JackAudio::setFreewheel(bool f) - { -// printf("JACK: setFreewheel %d\n", f); - jack_set_freewheel(_client, f); - } - -//--------------------------------------------------------- -// startTransport -//--------------------------------------------------------- - -void JackAudio::startTransport() - { -// printf("JACK: startTransport\n"); - jack_transport_start(_client); - } - -//--------------------------------------------------------- -// stopTransport -//--------------------------------------------------------- - -void JackAudio::stopTransport() - { -// printf("JACK: stopTransport\n"); - if (_client) - jack_transport_stop(_client); - } - -//--------------------------------------------------------- -// seekTransport -//--------------------------------------------------------- - -void JackAudio::seekTransport(unsigned frame) - { -// printf("JACK: seekTransport %d\n", frame); - jack_transport_locate(_client, frame); - } - -//--------------------------------------------------------- -// findPort -//--------------------------------------------------------- - -Port JackAudio::findPort(const QString& name) - { - if (_client == 0) { - printf("JackAudio(%p)::findPort(%s): _client==0\n", this, qPrintable(name)); - return Port(); - } - jack_port_t* port = jack_port_by_name(_client, name.toLatin1().data()); -// printf("Jack::findPort <%s>, %p\n", name.toLatin1().data(), port); - return (port == 0) ? Port() : Port(port); - } - -//--------------------------------------------------------- -// realtimePriority -// return zero if not running realtime -// can only be called if JACK client thread is already -// running -//--------------------------------------------------------- - -int JackAudio::realtimePriority() const - { - pthread_t t = jack_client_thread_id(_client); - int policy; - struct sched_param param; - memset(¶m, 0, sizeof(param)); - int rv = pthread_getschedparam(t, &policy, ¶m); - if (rv) { - perror("MusE: get jack schedule parameter"); - return 0; - } - if (policy != SCHED_FIFO) { - printf("JACK is not running realtime\n"); - return 0; - } - return param.sched_priority; - } - -//--------------------------------------------------------- -// initJackAudio -// return true if JACK not found -//--------------------------------------------------------- - -bool initJackAudio() - { - if (debugMsg) { - fprintf(stderr, "init Jack Audio\n"); - jack_set_error_function(jackError); - } - else - jack_set_error_function(noJackError); - - jack_client_t* client = 0; - jack_status_t status; - jack_options_t options = JackNullOption; - client = jack_client_open("MusE", options, &status); - if (!client) { - if (status & JackServerStarted) - printf("jack server started...\n"); - if (status & JackServerFailed) - printf("cannot connect to jack server\n"); - if (status & JackServerError) - printf("communication with jack server failed\n"); - if (status & JackShmFailure) - printf("jack cannot access shared memory\n"); - if (status & JackVersionError) - printf("jack server has wrong version\n"); - printf("cannot create jack client\n"); - return true; - } - - if (debugMsg) - fprintf(stderr, "init Jack Audio: register device\n"); - - jack_set_error_function(jackError); - if (debugMsg) - fprintf(stderr, "init Jack Audio: register device\n"); - - jackAudio = new JackAudio(client, jack_get_client_name(client)); - if (debugMsg) - fprintf(stderr, "init Jack Audio: register client\n"); - jackAudio->registerClient(); - AL::sampleRate = jack_get_sample_rate(client); - segmentSize = jack_get_buffer_size(client); - audioDriver = jackAudio; - return false; - } - -//--------------------------------------------------------- -// putEvent -//--------------------------------------------------------- - -void JackAudio::putEvent(Port port, const MidiEvent& e) - { - if (midiOutputTrace) { - printf("MidiOut<%s>: jackMidi: ", portName(port).toLatin1().data()); - e.dump(); - } - void* pb = jack_port_get_buffer(port.jackPort(), segmentSize); - int ft = e.time() - lastFrameTime(); - if (ft < 0 || ft >= (int)segmentSize) { - printf("JackAudio::putEvent: time out of range %d\n", ft); - if (ft < 0) - ft = 0; - if (ft > (int)segmentSize) - ft = segmentSize - 1; - } - switch(e.type()) { - case ME_NOTEON: - case ME_NOTEOFF: - case ME_POLYAFTER: - case ME_CONTROLLER: - case ME_PITCHBEND: - { -#ifdef JACK107 - unsigned char* p = jack_midi_event_reserve(pb, ft, 3); -#endif -#ifdef JACK103 - unsigned char* p = jack_midi_event_reserve(pb, ft, 3, segmentSize); -#endif - if (p == 0) { - fprintf(stderr, "JackMidi: buffer overflow, event lost\n"); - return; - } - p[0] = e.type() | e.channel(); - p[1] = e.dataA(); - p[2] = e.dataB(); - } - break; - - case ME_PROGRAM: - case ME_AFTERTOUCH: - { -#ifdef JACK107 - unsigned char* p = jack_midi_event_reserve(pb, ft, 2); -#endif -#ifdef JACK103 - unsigned char* p = jack_midi_event_reserve(pb, ft, 2, segmentSize); -#endif - if (p == 0) { - fprintf(stderr, "JackMidi: buffer overflow, event lost\n"); - return; - } - p[0] = e.type() | e.channel(); - p[1] = e.dataA(); - } - break; - case ME_SYSEX: - { - const unsigned char* data = e.data(); - int len = e.len(); -#ifdef JACK107 - unsigned char* p = jack_midi_event_reserve(pb, ft, len+2); -#endif -#ifdef JACK103 - unsigned char* p = jack_midi_event_reserve(pb, ft, len+2, segmentSize); -#endif - if (p == 0) { - fprintf(stderr, "JackMidi: buffer overflow, event lost\n"); - return; - } - p[0] = 0xf0; - p[len+1] = 0xf7; - memcpy(p+1, data, len); - } - break; - case ME_SONGPOS: - case ME_CLOCK: - case ME_START: - case ME_CONTINUE: - case ME_STOP: - printf("JackMidi: event type %x not supported\n", e.type()); - break; - } - } - -//--------------------------------------------------------- -// startMidiCycle -//--------------------------------------------------------- - -void JackAudio::startMidiCycle(Port port) - { - void* port_buf = jack_port_get_buffer(port.jackPort(), segmentSize); -#ifdef JACK107 - jack_midi_clear_buffer(port_buf); -#endif -#ifdef JACK103 - jack_midi_clear_buffer(port_buf, segmentSize); -#endif - } - diff --git a/muse/muse/driver/jackaudio.h b/muse/muse/driver/jackaudio.h deleted file mode 100644 index 0322b3b8..00000000 --- a/muse/muse/driver/jackaudio.h +++ /dev/null @@ -1,87 +0,0 @@ -//============================================================================= -// MusE -// Linux Music Editor -// $Id:$ -// -// Copyright (C) 2002-2006 by Werner Schweer and others -// -// This program is free software; you can redistribute it and/or modify -// it under the terms of the GNU General Public License version 2. -// -// This program 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 General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program; if not, write to the Free Software -// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -//============================================================================= - -#ifndef __JACKAUDIO_H__ -#define __JACKAUDIO_H__ - -#include "audiodev.h" - -//--------------------------------------------------------- -// JackAudio -//--------------------------------------------------------- - -class JackAudio : public AudioDriver { - jack_client_t* _client; - jack_position_t pos; - char jackRegisteredName[8]; - jack_transport_state_t transportState; - - public: - JackAudio(jack_client_t* cl, char * jack_id_string); - virtual ~JackAudio(); - - int getTransportState(); - virtual bool init(); - virtual void start(int); - virtual bool restart(); - virtual void stop (); - virtual void zeroClientPtr() { _client = 0; } - virtual float* getBuffer(Port port, unsigned long nframes) { - return (float*)jack_port_get_buffer(port.jackPort(), nframes); - } - - virtual QList outputPorts(bool midi); - virtual QList inputPorts(bool midi); - - virtual void registerClient(); - - virtual Port registerOutPort(const QString& name, bool midi); - virtual Port registerInPort(const QString& name, bool midi); - - virtual char* getJackName(); - - virtual void unregisterPort(Port); - virtual bool connect(Port, Port); - virtual bool disconnect(Port, Port); - virtual void setPortName(Port p, const QString& n) { - jack_port_set_name(p.jackPort(), n.toLatin1().data()); - } - virtual Port findPort(const QString& name); - virtual QString portName(Port); - virtual int realtimePriority() const; - virtual void startTransport(); - virtual void stopTransport(); - virtual void seekTransport(unsigned frame); - virtual void setFreewheel(bool f); - - jack_transport_state_t transportQuery(jack_position_t* pos) { - return jack_transport_query(_client, pos); - } - void graphChanged(); - virtual void putEvent(Port, const MidiEvent&); - virtual void startMidiCycle(Port); - - virtual unsigned lastFrameTime() const { return jack_last_frame_time(_client); } - virtual unsigned frameTime() const { return jack_frame_time(_client); } - virtual unsigned curFrame() const { return pos.frame; } - }; - -#endif - diff --git a/muse/muse/driver/port.h b/muse/muse/driver/port.h deleted file mode 100644 index d2f83de9..00000000 --- a/muse/muse/driver/port.h +++ /dev/null @@ -1,76 +0,0 @@ -//============================================================================= -// MusE -// Linux Music Editor -// $Id:$ -// -// Copyright (C) 2002-2006 by Werner Schweer and others -// -// This program is free software; you can redistribute it and/or modify -// it under the terms of the GNU General Public License version 2. -// -// This program 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 General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program; if not, write to the Free Software -// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. -//============================================================================= - -#ifndef __PORT_H__ -#define __PORT_H__ - -#include - -//--------------------------------------------------------- -// Port -//--------------------------------------------------------- - -class Port { - enum { JACK_TYPE, ALSA_TYPE, ZERO_TYPE } type; - union { - jack_port_t* _jackPort; - struct { - unsigned char _alsaPort; - unsigned char _alsaClient; - }; - }; - public: - Port() { - type = ZERO_TYPE; - } - Port(jack_port_t* p) { - _jackPort = p; - type = JACK_TYPE; - } - Port(unsigned char client, unsigned char port) { - _alsaPort = port; - _alsaClient = client; - type = ALSA_TYPE; - } - void setZero() { type = ZERO_TYPE; } - bool isZero() const { return type == ZERO_TYPE; } - bool operator==(const Port& p) const { - if (type == JACK_TYPE) - return _jackPort == p._jackPort; - else if (type == ALSA_TYPE) - return _alsaPort == p._alsaPort && _alsaClient == p._alsaClient; - else - return true; - } - bool operator<(const Port& p) const { - if (type == ALSA_TYPE) { - if (_alsaPort != p._alsaPort) - return _alsaPort < p._alsaPort; - return _alsaClient < p._alsaClient; - } - return false; - } - unsigned char alsaPort() const { return _alsaPort; } - unsigned char alsaClient() const { return _alsaClient; } - jack_port_t* jackPort() const { return _jackPort; } - }; - -#endif - diff --git a/muse/muse/dummyaudio.cpp b/muse/muse/dummyaudio.cpp new file mode 100644 index 00000000..b4bc73ff --- /dev/null +++ b/muse/muse/dummyaudio.cpp @@ -0,0 +1,294 @@ +//============================================================================= +// MusE +// Linux Music Editor +// $Id:$ +// +// Copyright (C) 2002-2006 by Werner Schweer and others +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2. +// +// This program 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 General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +//============================================================================= + +#include "al/al.h" +#include "widgets/utils.h" +#include "audio.h" +#include "audiodev.h" +#include "globals.h" +#include "song.h" + +static const unsigned dummyFrames = 1024; +static double startTime; + +//--------------------------------------------------------- +// DummyAudio +//--------------------------------------------------------- + +class DummyAudio : public AudioDriver { + float* buffer; + pthread_t dummyThread; + std::vector oPorts; + std::vector iPorts; + int realTimePriority; + + public: + int state; + bool seekflag; + unsigned pos; + + DummyAudio() { + state = Audio::STOP; + seekflag = false; + startTime = curTime(); + posix_memalign((void**)&buffer, 16, sizeof(float) * dummyFrames); + } + virtual ~DummyAudio() { + free(buffer); + } + + virtual bool init() { return true; } + virtual void start(int); + virtual void stop (); + virtual unsigned frameTime() const { + return lrint(curTime() * AL::sampleRate); + } + virtual unsigned lastFrameTime() const { + return lrint(startTime * AL::sampleRate); + } + virtual unsigned curFrame() const { return pos; } + + virtual float* getBuffer(Port /*port*/, unsigned long nframes) + { + if (nframes > dummyFrames) { + fprintf(stderr, "error: segment size > %d\n", dummyFrames); + exit(-1); + } + memset(buffer, 0, nframes * sizeof(float)); + return buffer; + } + + virtual QList outputPorts(bool midi = false); + virtual QList inputPorts(bool midi = false); + + virtual void registerClient() {} + + virtual Port registerOutPort(const QString& s, bool) { + iPorts.push_back(QString(s)); + Port port(0, iPorts.size() + 3000); + return port; + } + virtual Port registerInPort(const QString& s, bool) { + oPorts.push_back(QString(s)); + Port port(0, oPorts.size() + 40); + return port; + } + virtual void unregisterPort(Port) { +/* if (long(p) >= 100) + oPorts.erase(oPorts.begin() + (long(p)-40)); + else + iPorts.erase(iPorts.begin() + long(p)-30); +*/ + } + virtual bool connect(Port, Port) { return true; } + virtual bool disconnect(Port, Port) { return true; } + virtual void setPortName(Port, const QString&) {} + virtual Port findPort(const QString& s) { + if (s == "input1") + return Port(0, 10); + if (s == "input2") + return Port(0, 11); + if (s == "output1") + return Port(0, 20); + if (s == "output2") + return Port(0, 21); + int k = 0; + for (std::vector::const_iterator i = iPorts.begin(); i != iPorts.end(); ++i, ++k) { + if (s == *i) + return Port(0, 30+k); + } + k = 0; + for (std::vector::const_iterator i = oPorts.begin(); i != oPorts.end(); ++i, ++k) { + if (s == *i) + return Port(0, 40); + } + return Port(); + } + virtual QString portName(Port port) { + if (port.alsaPort() == 10) + return QString("input1"); + if (port.alsaPort() == 11) + return QString("input2"); + if (port.alsaPort() == 20) + return QString("output1"); + if (port.alsaPort() == 21) + return QString("output2"); + if (port.alsaPort() >= 40) + return QString(oPorts[port.alsaPort() - 40]); + else + return QString(iPorts[port.alsaPort() - 30]); + } + virtual int realtimePriority() const { return 40; } + virtual void startTransport() { + state = Audio::PLAY; + } + virtual void stopTransport() { + state = Audio::STOP; + } + virtual void seekTransport(unsigned n) { + seekflag = true; + pos = n; + } + virtual void setFreewheel(bool) {} + virtual void putEvent(Port, const MidiEvent&) {} + }; + +DummyAudio* dummyAudio; + +//--------------------------------------------------------- +// initDummyAudio +//--------------------------------------------------------- + +bool initDummyAudio() + { + dummyAudio = new DummyAudio(); + audioDriver = dummyAudio; + return false; + } + +//--------------------------------------------------------- +// outputPorts +//--------------------------------------------------------- + +QList DummyAudio::outputPorts(bool midi) + { + QList clientList; + if (!midi) { + PortName p1; + p1.name = QString("output1"); + p1.port = Port(0, 100); + PortName p2; + p2.name = QString("output2"); + p2.port = Port(0, 101); + clientList.append(p1); + clientList.append(p2); + } + return clientList; + } + +//--------------------------------------------------------- +// inputPorts +//--------------------------------------------------------- + +QList DummyAudio::inputPorts(bool midi) + { + QList clientList; + if (!midi) { + PortName p1; + p1.name = QString("input1"); + p1.port = Port(0, 0); + PortName p2; + p2.name = QString("input2"); + p2.port = Port(0, 1); + clientList.append(p1); + clientList.append(p2); + } + return clientList; + } + +//--------------------------------------------------------- +// dummyLoop +//--------------------------------------------------------- + +static void* dummyLoop(void*) + { +#ifndef __APPLE__ + if (realTimePriority) { + // + // check if we really got realtime priviledges + // + int policy; + if ((policy = sched_getscheduler (0)) < 0) { + printf("cannot get current client scheduler for audio dummy thread: %s!\n", strerror(errno)); + } + else + { + if (policy != SCHED_FIFO) + printf("audio dummy thread _NOT_ running SCHED_FIFO\n"); + else if (debugMsg) { + struct sched_param rt_param; + memset(&rt_param, 0, sizeof(sched_param)); + int type; + int rv = pthread_getschedparam(pthread_self(), &type, &rt_param); + if (rv == -1) + perror("get scheduler parameter"); + printf("audio dummy thread running SCHED_FIFO priority %d\n", + rt_param.sched_priority); + } + } + } +#endif + + for (;;) { + if (audioState == AUDIO_RUNNING) + audio->process(segmentSize, dummyAudio->state); + else if (audioState == AUDIO_START1) + audioState = AUDIO_START2; + usleep(dummyFrames*1000000/AL::sampleRate); + if (dummyAudio->seekflag) { + audio->sync(Audio::STOP, dummyAudio->pos); + dummyAudio->seekflag = false; + } + if (dummyAudio->state == Audio::PLAY) { + dummyAudio->pos += dummyFrames; + } + } + pthread_exit(0); + } + +//--------------------------------------------------------- +// start +//--------------------------------------------------------- + +void DummyAudio::start(int priority) + { + realTimePriority = priority; + pthread_attr_t* attributes = 0; + + if (priority) { + attributes = (pthread_attr_t*) malloc(sizeof(pthread_attr_t)); + pthread_attr_init(attributes); + + if (pthread_attr_setschedpolicy(attributes, SCHED_FIFO)) { + printf("cannot set FIFO scheduling class for RT thread\n"); + } + if (pthread_attr_setscope (attributes, PTHREAD_SCOPE_SYSTEM)) { + printf("Cannot set scheduling scope for RT thread\n"); + } + struct sched_param rt_param; + memset(&rt_param, 0, sizeof(rt_param)); + rt_param.sched_priority = priority; + if (pthread_attr_setschedparam (attributes, &rt_param)) { + printf("Cannot set scheduling priority %d for RT thread (%s)\n", + priority, strerror(errno)); + } + } + if (pthread_create(&dummyThread, attributes, ::dummyLoop, this)) + perror("creating thread failed:"); + if (priority) + pthread_attr_destroy(attributes); + } + +void DummyAudio::stop () + { + pthread_cancel(dummyThread); + pthread_join(dummyThread, 0); + } + diff --git a/muse/muse/jack.cpp b/muse/muse/jack.cpp new file mode 100644 index 00000000..cde57418 --- /dev/null +++ b/muse/muse/jack.cpp @@ -0,0 +1,931 @@ +//============================================================================= +// MusE +// Linux Music Editor +// $Id:$ +// +// Copyright (C) 2002-2006 by Werner Schweer and others +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2. +// +// This program 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 General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +//============================================================================= + +#include "config.h" +#include "al/al.h" +#include "al/tempo.h" +#include "audio.h" +#include "globals.h" +#include "song.h" +#include "jackaudio.h" +#include "track.h" + +#ifdef VST_SUPPORT +#include +#endif + +JackAudio* jackAudio; + +//--------------------------------------------------------- +// init +//--------------------------------------------------------- + +bool JackAudio::init() + { + return true; + } + +//--------------------------------------------------------- +// jack_thread_init +//--------------------------------------------------------- + +static void jack_thread_init (void* /*data*/) + { +#ifdef VST_SUPPORT + if (loadVST) + fst_adopt_thread(); +#endif + int policy; + if ( (policy = sched_getscheduler (0)) < 0) { + printf("cannot get current client scheduler for JACK thread: %s!\n", strerror(errno)); + } + else { + if (policy != SCHED_FIFO) + printf("JACK thread %d _NOT_ running SCHED_FIFO\n", getpid()); + else if (debugMsg) { + struct sched_param rt_param; + memset(&rt_param, 0, sizeof(sched_param)); + int type; + int rv = pthread_getschedparam(pthread_self(), &type, &rt_param); + if (rv == -1) + perror("get scheduler parameter"); + printf("JACK thread running SCHED_FIFO priority %d\n", + rt_param.sched_priority); + } + } + + } + +//--------------------------------------------------------- +// timebase_callback +//--------------------------------------------------------- + +static void timebase_callback(jack_transport_state_t /* state */, + jack_nframes_t /* nframes */, + jack_position_t* pos, + int /* new_pos */, + void*) + { + AL::Pos p(pos->frame, AL::FRAMES); + pos->valid = JackPositionBBT; + p.mbt(&pos->bar, &pos->beat, &pos->tick); + pos->bar++; + pos->beat++; + pos->bar_start_tick = Pos(pos->bar, 0, 0).tick(); + // + // dummy: + // + pos->beats_per_bar = 4; + pos->beat_type = 4; + pos->ticks_per_beat = 384; + int tempo = AL::tempomap.tempo(p.tick()); + pos->beats_per_minute = (60000000.0 / tempo) * AL::tempomap.globalTempo()/100.0; + } + +//--------------------------------------------------------- +// processAudio +// JACK callback +//--------------------------------------------------------- + +static int processAudio(jack_nframes_t frames, void*) + { +#if 0 + unsigned t1 = jackAudio->frameTime(); + unsigned t2 = jackAudio->lastFrameTime(); + unsigned t3 = jackAudio->framesSinceCyleStart(); + unsigned t4 = jackAudio->getCurFrame(); + +printf("cycle %8d %8d %8d %08d\n", t1, t2, t3, t4); +#endif + + int jackState = jackAudio->getTransportState(); + segmentSize = frames; + if (audioState == AUDIO_RUNNING) + audio->process((unsigned long)frames, jackState); + else if (audioState == AUDIO_STOP) { + if (debugMsg) + puts("jack calling when audio is stopped!\n"); + } + else if (audioState == AUDIO_START1) + audioState = AUDIO_START2; + return 0; + } + +//--------------------------------------------------------- +// getTransportState +//--------------------------------------------------------- + +int JackAudio::getTransportState() + { + int jackState; + transportState = jack_transport_query(_client, &pos); + switch (jackAudio->transportState) { + case JackTransportStopped: + jackState = Audio::STOP; + break; + case JackTransportLooping: + case JackTransportRolling: + jackState = Audio::PLAY; + break; + case JackTransportStarting: + jackState = Audio::START_PLAY; + break; + default: + jackState = Audio::STOP; + break; + } + return jackState; + } + +//--------------------------------------------------------- +// processSync +// return TRUE (non-zero) when ready to roll. +//--------------------------------------------------------- + +static int processSync(jack_transport_state_t state, jack_position_t* pos, void*) + { + int audioState = Audio::STOP; + switch (state) { + case JackTransportStopped: + audioState = Audio::STOP; + break; + case JackTransportLooping: + case JackTransportRolling: + audioState = Audio::PLAY; + break; + case JackTransportStarting: + audioState = Audio::START_PLAY; + break; + } + unsigned frame = pos->frame; + return audio->sync(audioState, frame); + } + +//--------------------------------------------------------- +// processShutdown +//--------------------------------------------------------- + +static void processShutdown(void*) + { + audio->shutdown(); + + for (int i = 0; i < 10; ++i) { + if (audioState == AUDIO_STOP) + break; + sleep(1); + } + if (audioState == AUDIO_RUNNING) + fprintf(stderr, "MusE: sequencer still running, something is very wrong.\n"); + jackAudio->zeroClientPtr(); // jack disconnect client no longer valid + } + +//--------------------------------------------------------- +// jackError +//--------------------------------------------------------- + +static void jackError(const char* s) + { + fprintf(stderr, "JACK ERROR: %s\n", s); + } + +//--------------------------------------------------------- +// noJackError +//--------------------------------------------------------- + +static void noJackError(const char* /* s */) + { + } + +//--------------------------------------------------------- +// JackAudio +//--------------------------------------------------------- + +JackAudio::JackAudio(jack_client_t* cl, char* name) + : AudioDriver() + { + strcpy(jackRegisteredName, name); + _client = cl; + } + +//--------------------------------------------------------- +// ~JackAudio +//--------------------------------------------------------- + +JackAudio::~JackAudio() + { + if (_client) { + if (jack_client_close(_client)) { + fprintf(stderr, "jack_client_close() failed: %s\n", + strerror(errno)); + } + } + _client = 0; + } + +//--------------------------------------------------------- +// getJackName() +//--------------------------------------------------------- + +char* JackAudio::getJackName() + { + return jackRegisteredName; + } + +//--------------------------------------------------------- +// restart +//--------------------------------------------------------- + +bool JackAudio::restart() + { + printf("JackAudio::restart\n"); + _client = jack_client_new(jackRegisteredName); + if (!_client) + return true; + registerClient(); + return false; + } + +//--------------------------------------------------------- +// bufsize_callback +//--------------------------------------------------------- + +static int bufsize_callback(jack_nframes_t n, void*) + { + printf("JACK: buffersize changed %d\n", n); + return 0; + } + +//--------------------------------------------------------- +// freewheel_callback +//--------------------------------------------------------- + +static void freewheel_callback(int starting, void*) + { + audio->setFreewheel(starting); + } + +//--------------------------------------------------------- +// srate_callback +//--------------------------------------------------------- + +static int srate_callback(jack_nframes_t n, void*) + { + if (debugMsg) + printf("JACK: sample rate changed: %d\n", n); + return 0; + } + +//--------------------------------------------------------- +// registration_callback +//--------------------------------------------------------- + +static void registration_callback(jack_port_id_t, int, void*) + { + if (debugMsg) + printf("JACK: registration changed\n"); + } + +//--------------------------------------------------------- +// graph_callback +// this is called from jack when the connections +// changed +//--------------------------------------------------------- + +static int graph_callback(void*) + { + // we cannot call JackAudio::graphChanged() from this + // context, so we send a message to the gui thread which in turn + // calls graphChanged() + + audio->sendMsgToGui(MSG_GRAPH_CHANGED); + if (debugMsg) + printf("JACK: graph changed!\n"); + return 0; + } + +//--------------------------------------------------------- +// JackAudio::graphChanged +// this is called from song in gui context triggered +// by graph_callback() +//--------------------------------------------------------- + +void JackAudio::graphChanged() + { + RouteList rr, ra; + + InputList* il = song->inputs(); + for (iAudioInput ii = il->begin(); ii != il->end(); ++ii) { + AudioInput* it = *ii; + int channels = it->channels(); + RouteList* irl = it->inRoutes(); + + for (int channel = 0; channel < channels; ++channel) { + jack_port_t* port = it->jackPort(channel).jackPort(); + if (port == 0) + continue; + const char** ports = jack_port_get_all_connections(_client, port); + + //--------------------------------------- + // check for disconnects + //--------------------------------------- + + foreach (const Route& r, *irl) { + if (r.dst.channel != channel) + continue; + const char* name = jack_port_name(r.src.port.jackPort()); + bool found = false; + for (const char** pn = ports; pn && *pn; ++pn) { + if (strcmp(*pn, name) == 0) { + found = true; + break; + } + } + if (!found) + rr.append(r); + } + + //--------------------------------------- + // check for connects + //--------------------------------------- + + if (ports) { + for (const char** pn = ports; *pn; ++pn) { + bool found = false; + foreach(const Route& r, *irl) { + if (r.dst.channel != channel) + continue; + const char* name = jack_port_name(r.src.port.jackPort()); + if (strcmp(*pn, name) == 0) { + found = true; + break; + } + } + if (!found) { + Route a; + Port port(jack_port_by_name(_client, *pn)); + a.src = RouteNode(port, -1, RouteNode::AUDIOPORT); + a.dst = RouteNode(it, channel); + ra.append(a); + } + } + free(ports); + } + } + } + +// printf(" input: remove %d add %d routes\n", rr.size(), ra.size()); + foreach(Route r, rr) + audio->msgRemoveRoute1(r); + foreach(Route r, ra) + audio->msgAddRoute1(r); + rr.clear(); + ra.clear(); + + OutputList* ol = song->outputs(); + for (iAudioOutput ii = ol->begin(); ii != ol->end(); ++ii) { + AudioOutput* it = *ii; + int channels = it->channels(); + for (int channel = 0; channel < channels; ++channel) { + jack_port_t* port = it->jackPort(channel).jackPort(); + if (port == 0) + continue; + const char** ports = jack_port_get_all_connections(_client, port); + RouteList* rl = it->outRoutes(); + + //--------------------------------------- + // check for disconnects + //--------------------------------------- + + foreach(const Route& r, *rl) { + if (r.src.channel != channel) + continue; + const char* name = jack_port_name(r.dst.port.jackPort()); + bool found = false; + const char** pn = ports; + while (pn && *pn) { + if (strcmp(*pn, name) == 0) { + found = true; + break; + } + ++pn; + } + if (!found) + rr.append(r); + } + + //--------------------------------------- + // check for connects + //--------------------------------------- + + if (ports) { + const char** pn = ports; + while (*pn) { + bool found = false; + foreach (const Route& r, *rl) { + if (r.src.channel != channel) + continue; + const char* name = jack_port_name(r.dst.port.jackPort()); + if (strcmp(*pn, name) == 0) { + found = true; + break; + } + } + if (!found) { + Route a; + Port port(jack_port_by_name(_client, *pn)); + a.src = RouteNode(it, channel, RouteNode::TRACK); + a.dst = RouteNode(port, -1, RouteNode::AUDIOPORT); + ra.append(a); + } + ++pn; + } + free(ports); + } + } + } +// printf(" output: remove %d add %d routes\n", rr.size(), ra.size()); + foreach(Route r, rr) + audio->msgRemoveRoute1(r); + foreach(Route r, ra) + audio->msgAddRoute1(r); + } + +//static int xrun_callback(void*) +// { +// printf("JACK: xrun\n"); +// return 0; +// } + +//--------------------------------------------------------- +// register +//--------------------------------------------------------- + +void JackAudio::registerClient() + { + jack_set_process_callback(_client, processAudio, 0); + jack_set_sync_callback(_client, processSync, 0); + jack_on_shutdown(_client, processShutdown, 0); + jack_set_buffer_size_callback(_client, bufsize_callback, 0); + jack_set_sample_rate_callback(_client, srate_callback, 0); + jack_set_port_registration_callback(_client, registration_callback, 0); + jack_set_graph_order_callback(_client, graph_callback, 0); +// jack_set_xrun_callback(_client, xrun_callback, 0); + jack_set_freewheel_callback (_client, freewheel_callback, 0); + jack_set_thread_init_callback(_client, (JackThreadInitCallback) jack_thread_init, 0); + jack_set_timebase_callback(_client, 0, timebase_callback, 0); + } + +//--------------------------------------------------------- +// registerInPort +//--------------------------------------------------------- + +Port JackAudio::registerInPort(const QString& name, bool midi) + { + const char* type = midi ? JACK_DEFAULT_MIDI_TYPE : JACK_DEFAULT_AUDIO_TYPE; + Port p(jack_port_register(_client, name.toLatin1().data(), type, JackPortIsInput, 0)); +// printf("JACK: registerInPort<%s>: <%s> %p\n", type, name.toLatin1().data(), p.jackPort()); + if (!p.jackPort()) + p.setZero(); + return p; + } + +//--------------------------------------------------------- +// registerOutPort +//--------------------------------------------------------- + +Port JackAudio::registerOutPort(const QString& name, bool midi) + { + const char* type = midi ? JACK_DEFAULT_MIDI_TYPE : JACK_DEFAULT_AUDIO_TYPE; + Port p(jack_port_register(_client, name.toLatin1().data(), type, JackPortIsOutput, 0)); +// printf("JACK: registerOutPort<%s>: <%s> %p\n", type, name.toLatin1().data(), p.jackPort()); +#if 0 + if (midi) { + jack_nframes_t nframes = jack_get_buffer_size(_client); + jack_midi_reset_new_port(jack_port_get_buffer(p.jackPort(), nframes), nframes); + } +#endif + if (!p.jackPort()) + p.setZero(); + return p; + } + +//--------------------------------------------------------- +// exitJackAudio +//--------------------------------------------------------- + +void exitJackAudio() + { + if (jackAudio) + delete jackAudio; + } + +//--------------------------------------------------------- +// connect +// return false on error +//--------------------------------------------------------- + +bool JackAudio::connect(Port src, Port dst) + { + if (src.isZero() || dst.isZero()) { + fprintf(stderr, "JackAudio::connect(1): unknown jack ports (%d-%d)\n", + src.isZero(), dst.isZero()); + return false; + } + const char* sn = jack_port_name(src.jackPort()); + const char* dn = jack_port_name(dst.jackPort()); + + if (debugMsg) + printf("jack connect <%s>%p - <%s>%p\n", sn, src.jackPort(), dn, dst.jackPort()); + + if (sn == 0 || dn == 0) { + fprintf(stderr, "JackAudio::connect(2): unknown jack ports\n"); + return false; + } + int rv = jack_connect(_client, sn, dn); + if (rv) { + fprintf(stderr, "%d: jack connect <%s> - <%s> failed\n", + rv, sn, dn); + if (rv == EEXIST) + fprintf(stderr, " connection already made\n"); + else { + int pf = jack_port_flags(src.jackPort()); + if (!(pf & JackPortIsOutput)) + fprintf(stderr, " src is not an output port\n"); + pf = jack_port_flags(dst.jackPort()); + if (!(pf & JackPortIsInput)) + fprintf(stderr, " dst is not an input port\n"); + } + return false; + } + return true; + } + +//--------------------------------------------------------- +// disconnect +//--------------------------------------------------------- + +bool JackAudio::disconnect(Port src, Port dst) + { + const char* sn = jack_port_name(src.jackPort()); + const char* dn = jack_port_name(dst.jackPort()); + + if (debugMsg) + printf("jack disconnect <%s>%p - <%s>%p\n", sn, src.jackPort(), dn, dst.jackPort()); + + if (sn == 0 || dn == 0) { + fprintf(stderr, "JackAudio::disconnect: unknown jack ports\n"); + return false; + } + if (jack_disconnect(_client, sn, dn)) { + fprintf(stderr, "jack disconnect <%s> - <%s> failed\n", + sn, dn); + return false; + } + return true; + } + +//--------------------------------------------------------- +// start +//--------------------------------------------------------- + +void JackAudio::start(int) + { + if (jack_activate(_client)) { + fprintf (stderr, "JACK: cannot activate client\n"); + exit(-1); + } + } + +//--------------------------------------------------------- +// stop +//--------------------------------------------------------- + +void JackAudio::stop() + { + if (_client == 0) + return; + if (jack_deactivate(_client)) + fprintf (stderr, "JACK: cannot deactivate client\n"); + } + +//--------------------------------------------------------- +// outputPorts +//--------------------------------------------------------- + +QList JackAudio::outputPorts(bool midi) + { + const char* type = midi ? JACK_DEFAULT_MIDI_TYPE : JACK_DEFAULT_AUDIO_TYPE; + const char** ports = jack_get_ports(_client, 0, type, JackPortIsOutput); + QList clientList; + for (const char** p = ports; p && *p; ++p) { + jack_port_t* port = jack_port_by_name(_client, *p); + char buffer[128]; + strncpy(buffer, *p, 128); + if (strncmp(buffer, "MusE", 4) == 0) + continue; + PortName pn; + pn.name = QString(buffer); + pn.port = Port(port); + clientList.append(pn); + } + return clientList; + } + +//--------------------------------------------------------- +// inputPorts +//--------------------------------------------------------- + +QList JackAudio::inputPorts(bool midi) + { + const char* type = midi ? JACK_DEFAULT_MIDI_TYPE : JACK_DEFAULT_AUDIO_TYPE; + const char** ports = jack_get_ports(_client, 0, type, JackPortIsInput); + QList clientList; + for (const char** p = ports; p && *p; ++p) { + jack_port_t* port = jack_port_by_name(_client, *p); + char buffer[128]; + strncpy(buffer, *p, 128); + if (strncmp(buffer, "MusE", 4) == 0) + continue; + PortName pn; + pn.name = QString(buffer); + pn.port = Port(port); + clientList.append(pn); + } + return clientList; + } + +//--------------------------------------------------------- +// portName +//--------------------------------------------------------- + +QString JackAudio::portName(Port port) + { + const char* nameStrPtr = jack_port_name(port.jackPort()); + QString s(nameStrPtr); + return s; + } + +//--------------------------------------------------------- +// unregisterPort +//--------------------------------------------------------- + +void JackAudio::unregisterPort(Port p) + { + if (_client) { +// printf("JACK: unregister Port %p\n", p); + if (jack_port_unregister(_client, p.jackPort())) + fprintf(stderr, "jack unregister port %p failed\n", p.jackPort()); + } + } + +//--------------------------------------------------------- +// setFreewheel +//--------------------------------------------------------- + +void JackAudio::setFreewheel(bool f) + { +// printf("JACK: setFreewheel %d\n", f); + jack_set_freewheel(_client, f); + } + +//--------------------------------------------------------- +// startTransport +//--------------------------------------------------------- + +void JackAudio::startTransport() + { +// printf("JACK: startTransport\n"); + jack_transport_start(_client); + } + +//--------------------------------------------------------- +// stopTransport +//--------------------------------------------------------- + +void JackAudio::stopTransport() + { +// printf("JACK: stopTransport\n"); + if (_client) + jack_transport_stop(_client); + } + +//--------------------------------------------------------- +// seekTransport +//--------------------------------------------------------- + +void JackAudio::seekTransport(unsigned frame) + { +// printf("JACK: seekTransport %d\n", frame); + jack_transport_locate(_client, frame); + } + +//--------------------------------------------------------- +// findPort +//--------------------------------------------------------- + +Port JackAudio::findPort(const QString& name) + { + if (_client == 0) { + printf("JackAudio(%p)::findPort(%s): _client==0\n", this, qPrintable(name)); + return Port(); + } + jack_port_t* port = jack_port_by_name(_client, name.toLatin1().data()); +// printf("Jack::findPort <%s>, %p\n", name.toLatin1().data(), port); + return (port == 0) ? Port() : Port(port); + } + +//--------------------------------------------------------- +// realtimePriority +// return zero if not running realtime +// can only be called if JACK client thread is already +// running +//--------------------------------------------------------- + +int JackAudio::realtimePriority() const + { + pthread_t t = jack_client_thread_id(_client); + int policy; + struct sched_param param; + memset(¶m, 0, sizeof(param)); + int rv = pthread_getschedparam(t, &policy, ¶m); + if (rv) { + perror("MusE: get jack schedule parameter"); + return 0; + } + if (policy != SCHED_FIFO) { + printf("JACK is not running realtime\n"); + return 0; + } + return param.sched_priority; + } + +//--------------------------------------------------------- +// initJackAudio +// return true if JACK not found +//--------------------------------------------------------- + +bool initJackAudio() + { + if (debugMsg) { + fprintf(stderr, "init Jack Audio\n"); + jack_set_error_function(jackError); + } + else + jack_set_error_function(noJackError); + + jack_client_t* client = 0; + jack_status_t status; + jack_options_t options = JackNullOption; + client = jack_client_open("MusE", options, &status); + if (!client) { + if (status & JackServerStarted) + printf("jack server started...\n"); + if (status & JackServerFailed) + printf("cannot connect to jack server\n"); + if (status & JackServerError) + printf("communication with jack server failed\n"); + if (status & JackShmFailure) + printf("jack cannot access shared memory\n"); + if (status & JackVersionError) + printf("jack server has wrong version\n"); + printf("cannot create jack client\n"); + return true; + } + + if (debugMsg) + fprintf(stderr, "init Jack Audio: register device\n"); + + jack_set_error_function(jackError); + if (debugMsg) + fprintf(stderr, "init Jack Audio: register device\n"); + + jackAudio = new JackAudio(client, jack_get_client_name(client)); + if (debugMsg) + fprintf(stderr, "init Jack Audio: register client\n"); + jackAudio->registerClient(); + AL::sampleRate = jack_get_sample_rate(client); + segmentSize = jack_get_buffer_size(client); + audioDriver = jackAudio; + return false; + } + +//--------------------------------------------------------- +// putEvent +//--------------------------------------------------------- + +void JackAudio::putEvent(Port port, const MidiEvent& e) + { + if (midiOutputTrace) { + printf("MidiOut<%s>: jackMidi: ", portName(port).toLatin1().data()); + e.dump(); + } + void* pb = jack_port_get_buffer(port.jackPort(), segmentSize); + int ft = e.time() - lastFrameTime(); + if (ft < 0 || ft >= (int)segmentSize) { + printf("JackAudio::putEvent: time out of range %d\n", ft); + if (ft < 0) + ft = 0; + if (ft > (int)segmentSize) + ft = segmentSize - 1; + } + switch(e.type()) { + case ME_NOTEON: + case ME_NOTEOFF: + case ME_POLYAFTER: + case ME_CONTROLLER: + case ME_PITCHBEND: + { +#ifdef JACK107 + unsigned char* p = jack_midi_event_reserve(pb, ft, 3); +#endif +#ifdef JACK103 + unsigned char* p = jack_midi_event_reserve(pb, ft, 3, segmentSize); +#endif + if (p == 0) { + fprintf(stderr, "JackMidi: buffer overflow, event lost\n"); + return; + } + p[0] = e.type() | e.channel(); + p[1] = e.dataA(); + p[2] = e.dataB(); + } + break; + + case ME_PROGRAM: + case ME_AFTERTOUCH: + { +#ifdef JACK107 + unsigned char* p = jack_midi_event_reserve(pb, ft, 2); +#endif +#ifdef JACK103 + unsigned char* p = jack_midi_event_reserve(pb, ft, 2, segmentSize); +#endif + if (p == 0) { + fprintf(stderr, "JackMidi: buffer overflow, event lost\n"); + return; + } + p[0] = e.type() | e.channel(); + p[1] = e.dataA(); + } + break; + case ME_SYSEX: + { + const unsigned char* data = e.data(); + int len = e.len(); +#ifdef JACK107 + unsigned char* p = jack_midi_event_reserve(pb, ft, len+2); +#endif +#ifdef JACK103 + unsigned char* p = jack_midi_event_reserve(pb, ft, len+2, segmentSize); +#endif + if (p == 0) { + fprintf(stderr, "JackMidi: buffer overflow, event lost\n"); + return; + } + p[0] = 0xf0; + p[len+1] = 0xf7; + memcpy(p+1, data, len); + } + break; + case ME_SONGPOS: + case ME_CLOCK: + case ME_START: + case ME_CONTINUE: + case ME_STOP: + printf("JackMidi: event type %x not supported\n", e.type()); + break; + } + } + +//--------------------------------------------------------- +// startMidiCycle +//--------------------------------------------------------- + +void JackAudio::startMidiCycle(Port port) + { + void* port_buf = jack_port_get_buffer(port.jackPort(), segmentSize); +#ifdef JACK107 + jack_midi_clear_buffer(port_buf); +#endif +#ifdef JACK103 + jack_midi_clear_buffer(port_buf, segmentSize); +#endif + } + diff --git a/muse/muse/jackaudio.h b/muse/muse/jackaudio.h new file mode 100644 index 00000000..0322b3b8 --- /dev/null +++ b/muse/muse/jackaudio.h @@ -0,0 +1,87 @@ +//============================================================================= +// MusE +// Linux Music Editor +// $Id:$ +// +// Copyright (C) 2002-2006 by Werner Schweer and others +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2. +// +// This program 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 General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +//============================================================================= + +#ifndef __JACKAUDIO_H__ +#define __JACKAUDIO_H__ + +#include "audiodev.h" + +//--------------------------------------------------------- +// JackAudio +//--------------------------------------------------------- + +class JackAudio : public AudioDriver { + jack_client_t* _client; + jack_position_t pos; + char jackRegisteredName[8]; + jack_transport_state_t transportState; + + public: + JackAudio(jack_client_t* cl, char * jack_id_string); + virtual ~JackAudio(); + + int getTransportState(); + virtual bool init(); + virtual void start(int); + virtual bool restart(); + virtual void stop (); + virtual void zeroClientPtr() { _client = 0; } + virtual float* getBuffer(Port port, unsigned long nframes) { + return (float*)jack_port_get_buffer(port.jackPort(), nframes); + } + + virtual QList outputPorts(bool midi); + virtual QList inputPorts(bool midi); + + virtual void registerClient(); + + virtual Port registerOutPort(const QString& name, bool midi); + virtual Port registerInPort(const QString& name, bool midi); + + virtual char* getJackName(); + + virtual void unregisterPort(Port); + virtual bool connect(Port, Port); + virtual bool disconnect(Port, Port); + virtual void setPortName(Port p, const QString& n) { + jack_port_set_name(p.jackPort(), n.toLatin1().data()); + } + virtual Port findPort(const QString& name); + virtual QString portName(Port); + virtual int realtimePriority() const; + virtual void startTransport(); + virtual void stopTransport(); + virtual void seekTransport(unsigned frame); + virtual void setFreewheel(bool f); + + jack_transport_state_t transportQuery(jack_position_t* pos) { + return jack_transport_query(_client, pos); + } + void graphChanged(); + virtual void putEvent(Port, const MidiEvent&); + virtual void startMidiCycle(Port); + + virtual unsigned lastFrameTime() const { return jack_last_frame_time(_client); } + virtual unsigned frameTime() const { return jack_frame_time(_client); } + virtual unsigned curFrame() const { return pos.frame; } + }; + +#endif + diff --git a/muse/muse/port.h b/muse/muse/port.h new file mode 100644 index 00000000..d2f83de9 --- /dev/null +++ b/muse/muse/port.h @@ -0,0 +1,76 @@ +//============================================================================= +// MusE +// Linux Music Editor +// $Id:$ +// +// Copyright (C) 2002-2006 by Werner Schweer and others +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License version 2. +// +// This program 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 General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program; if not, write to the Free Software +// Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. +//============================================================================= + +#ifndef __PORT_H__ +#define __PORT_H__ + +#include + +//--------------------------------------------------------- +// Port +//--------------------------------------------------------- + +class Port { + enum { JACK_TYPE, ALSA_TYPE, ZERO_TYPE } type; + union { + jack_port_t* _jackPort; + struct { + unsigned char _alsaPort; + unsigned char _alsaClient; + }; + }; + public: + Port() { + type = ZERO_TYPE; + } + Port(jack_port_t* p) { + _jackPort = p; + type = JACK_TYPE; + } + Port(unsigned char client, unsigned char port) { + _alsaPort = port; + _alsaClient = client; + type = ALSA_TYPE; + } + void setZero() { type = ZERO_TYPE; } + bool isZero() const { return type == ZERO_TYPE; } + bool operator==(const Port& p) const { + if (type == JACK_TYPE) + return _jackPort == p._jackPort; + else if (type == ALSA_TYPE) + return _alsaPort == p._alsaPort && _alsaClient == p._alsaClient; + else + return true; + } + bool operator<(const Port& p) const { + if (type == ALSA_TYPE) { + if (_alsaPort != p._alsaPort) + return _alsaPort < p._alsaPort; + return _alsaClient < p._alsaClient; + } + return false; + } + unsigned char alsaPort() const { return _alsaPort; } + unsigned char alsaClient() const { return _alsaClient; } + jack_port_t* jackPort() const { return _jackPort; } + }; + +#endif + -- cgit v1.2.3