|
- /*
- 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 the GNU General Public License
- as published by the Free Software Foundation; either version 2
- of the License, or (at your option) any later version.
- */
-
- #include <jack/jack.h>
- #include <string>
- #include <cstring>
- #include <err.h>
- #include <cstdio>
- #include <cassert>
-
- #include "Nio.h"
- #include "../Misc/Util.h"
- #include "../Misc/Master.h"
- #include "../Misc/Part.h"
- #include "../Misc/MiddleWare.h"
-
- #include "JackMultiEngine.h"
-
- extern zyncarla::MiddleWare *middleware;
-
- namespace zyncarla {
-
- using std::string;
-
- struct jack_multi
- {
- jack_port_t *ports[NUM_MIDI_PARTS * 2 + 2];
- jack_client_t *client;
- bool running;
- };
-
- JackMultiEngine::JackMultiEngine(const SYNTH_T &synth)
- :AudioOut(synth), 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;
- if(Nio::pidInClientName)
- clientname += "_" + os_pid_as_padded_string();
- 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) {
- //Abort if ports are only partially initialized
- if(!impl->ports[i])
- return false;
-
- 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 = *middleware->spawnMaster();
- 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 false;
- }
-
- 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);
- }
-
- if(impl->client)
- jack_client_close(impl->client);
- impl->client = NULL;
-
- impl->running = false;
- }
-
- }
|