zynaddsubfx

ZynAddSubFX open source synthesizer
Log | Files | Refs | Submodules | LICENSE

commit e08be6ab5b79345f2dd21bd8f577468ae8e4e25c
parent e704711a009fd582bc874de1d85064de1afb4d77
Author: fundamental <mark.d.mccurry@gmail.com>
Date:   Mon,  2 Feb 2015 19:15:11 -0500

Merge branch 'multi-jack'

Diffstat:
Msrc/Nio/CMakeLists.txt | 2+-
Msrc/Nio/EngineMgr.cpp | 2++
Asrc/Nio/JackMultiEngine.cpp | 171+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/Nio/JackMultiEngine.h | 46++++++++++++++++++++++++++++++++++++++++++++++
Msrc/main.cpp | 15++++++++-------
5 files changed, 228 insertions(+), 8 deletions(-)

diff --git a/src/Nio/CMakeLists.txt b/src/Nio/CMakeLists.txt @@ -22,7 +22,7 @@ add_definitions(-DIN_DEFAULT="${DefaultInput}") if(JackEnable) include_directories(${JACK_INCLUDE_DIR}) - list(APPEND zynaddsubfx_nio_SRCS JackEngine.cpp) + list(APPEND zynaddsubfx_nio_SRCS JackEngine.cpp JackMultiEngine.cpp) list(APPEND zynaddsubfx_nio_lib ${JACK_LIBRARIES}) CHECK_INCLUDE_FILES("jack/metadata.h" JACK_HAS_METADATA_API) diff --git a/src/Nio/EngineMgr.cpp b/src/Nio/EngineMgr.cpp @@ -16,6 +16,7 @@ #endif #if JACK #include "JackEngine.h" +#include "JackMultiEngine.h" #endif #if PORTAUDIO #include "PaEngine.h" @@ -44,6 +45,7 @@ EngineMgr::EngineMgr() #endif #if JACK engines.push_back(new JackEngine()); + engines.push_back(new JackMultiEngine()); #endif #if PORTAUDIO engines.push_back(new PaEngine()); diff --git a/src/Nio/JackMultiEngine.cpp b/src/Nio/JackMultiEngine.cpp @@ -0,0 +1,171 @@ +/* + ZynAddSubFX - a software synthesizer + + JackMultiEngine.cpp - Channeled Audio output JACK + Copyright (C) 2012-2012 Mark McCurry + Author: Mark McCurry + + This program is free software; you can redistribute it and/or modify + it under the terms of version 2 of the GNU General Public License + as published by the Free Software Foundation. + + 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 (version 2 or later) for more details. + + You should have received a copy of the GNU General Public License (version 2) + along with this program; if not, write to the Free Software Foundation, + Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +*/ + +#include <jack/jack.h> +#include <string> +#include <cstring> +#include <err.h> +#include <cstdio> +#include <cassert> + +#include "Nio.h" +#include "../Misc/Master.h" +#include "../Misc/Part.h" + +#include "JackMultiEngine.h" + +using std::string; + +struct jack_multi +{ + jack_port_t *ports[NUM_MIDI_PARTS * 2 + 2]; + jack_client_t *client; + bool running; +}; + +JackMultiEngine::JackMultiEngine(void) + :impl(new jack_multi()) +{ + impl->running = false; + impl->client = NULL; + + name = "JACK-MULTI"; +} + +JackMultiEngine::~JackMultiEngine(void) +{ + delete impl; +} + +void JackMultiEngine::setAudioEn(bool nval) +{ + if(nval) + Start(); + else + Stop(); +} + +bool JackMultiEngine::getAudioEn() const +{ + return impl->running; +} + + + +bool JackMultiEngine::Start(void) +{ + if(impl->client) + return true; + + string clientname = "zynaddsubfx"; + string postfix = Nio::getPostfix(); + if(!postfix.empty()) + clientname += "_" + postfix; + jack_status_t jackstatus; + + impl->client = jack_client_open(clientname.c_str(), JackNullOption, &jackstatus); + + if(!impl->client) + errx(1, "failed to connect to jack..."); + + + //Create the set of jack ports + char portName[20]; + memset(portName,0,sizeof(portName)); + +#define JACK_REGISTER(x) jack_port_register(impl->client, x, \ + JACK_DEFAULT_AUDIO_TYPE, JackPortIsOutput | JackPortIsTerminal, 0) + //Create the master wet port + + impl->ports[0] = JACK_REGISTER("out-L"); + impl->ports[1] = JACK_REGISTER("out-R"); + + //Create all part's outputs + for(int i = 0; i < NUM_MIDI_PARTS * 2; i += 2) { + snprintf(portName, 19, "part%d/out-L", i / 2); + impl->ports[2 + i] = JACK_REGISTER(portName); + snprintf(portName, 19, "part%d/out-R", i / 2); + impl->ports[3 + i] = JACK_REGISTER(portName); + } + + //verify that all sample rate and buffer_size are the same in jack. + //This insures that the connection can be made with no resampling or + //buffering + if(synth->samplerate != jack_get_sample_rate(impl->client)) + errx(1, "jack must have the same sample rate!"); + if(synth->buffersize != (int) jack_get_buffer_size(impl->client)) + errx(1, "jack must have the same buffer size"); + + jack_set_process_callback(impl->client, _processCallback, this); + + //run + if(jack_activate(impl->client)) + errx(1, "failed at starting the jack client"); + impl->running = true; + return true; +} + +int JackMultiEngine::_processCallback(jack_nframes_t nframes, void *arg) +{ + return static_cast<JackMultiEngine *>(arg)->processAudio(nframes); +} + +int JackMultiEngine::processAudio(jack_nframes_t nframes) +{ + //Gather all buffers + float *buffers[NUM_MIDI_PARTS * 2 + 2]; + + for(int i = 0; i < NUM_MIDI_PARTS * 2 + 2; ++i) { + buffers[i] = + (float *)jack_port_get_buffer(impl->ports[i], nframes); + assert(buffers[i]); + } + + //Get the wet samples from OutMgr + Stereo<float *> smp = getNext(); + memcpy(buffers[0], smp.l, synth->bufferbytes); + memcpy(buffers[1], smp.r, synth->bufferbytes); + + //Gather other samples from individual parts + Master &master = Master::getInstance(); + for(int i = 0; i < NUM_MIDI_PARTS; ++i) { + memcpy(buffers[2*i + 2], master.part[i]->partoutl, synth->bufferbytes); + memcpy(buffers[2*i + 3], master.part[i]->partoutr, synth->bufferbytes); + } + + return true; +} + +void JackMultiEngine::Stop() +{ + for(int i = 0; i < NUM_MIDI_PARTS * 2 + 2; ++i) { + jack_port_t *port = impl->ports[i]; + impl->ports[i] = NULL; + if(port) + jack_port_unregister(impl->client, port); + } + + jack_client_close(impl->client); + impl->client = NULL; + + impl->running = false; +} diff --git a/src/Nio/JackMultiEngine.h b/src/Nio/JackMultiEngine.h @@ -0,0 +1,46 @@ +/* + ZynAddSubFX - a software synthesizer + + JackMultiEngine.h - Channeled Audio output JACK + Copyright (C) 2012-2012 Mark McCurry + Author: Mark McCurry + + This program is free software; you can redistribute it and/or modify + it under the terms of version 2 of the GNU General Public License + as published by the Free Software Foundation. + + 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 (version 2 or later) for more details. + + You should have received a copy of the GNU General Public License (version 2) + along with this program; if not, write to the Free Software Foundation, + Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + +*/ +#ifndef JACK_MULTI_ENGINE +#define JACK_MULTI_ENGINE + +#include "AudioOut.h" + +class JackMultiEngine:public AudioOut +{ + public: + JackMultiEngine(void); + ~JackMultiEngine(void); + + void setAudioEn(bool nval); + bool getAudioEn() const; + + bool Start(void); + void Stop(void); + + private: + static int _processCallback(unsigned nframes, void *arg); + int processAudio(unsigned nframes); + + struct jack_multi *impl; +}; + +#endif diff --git a/src/main.cpp b/src/main.cpp @@ -96,13 +96,6 @@ void sigterm_exit(int /*sig*/) */ void initprogram(void) { - cerr.precision(1); - cerr << std::fixed; - cerr << "\nSample Rate = \t\t" << synth->samplerate << endl; - cerr << "Sound Buffer Size = \t" << synth->buffersize << " samples" << endl; - cerr << "Internal latency = \t" << synth->buffersize_f * 1000.0f - / synth->samplerate_f << " ms" << endl; - cerr << "ADsynth Oscil.Size = \t" << synth->oscilsize << " samples" << endl; middleware = new MiddleWare(); @@ -414,6 +407,14 @@ int main(int argc, char *argv[]) //Run the Nio system bool ioGood = Nio::start(); + + cerr.precision(1); + cerr << std::fixed; + cerr << "\nSample Rate = \t\t" << synth->samplerate << endl; + cerr << "Sound Buffer Size = \t" << synth->buffersize << " samples" << endl; + cerr << "Internal latency = \t" << synth->buffersize_f * 1000.0f + / synth->samplerate_f << " ms" << endl; + cerr << "ADsynth Oscil.Size = \t" << synth->oscilsize << " samples" << endl; if(!execAfterInit.empty()) { cout << "Executing user supplied command: " << execAfterInit << endl;