zynaddsubfx

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

JackMultiEngine.cpp (5558B)


      1 /*
      2   ZynAddSubFX - a software synthesizer
      3 
      4   JackMultiEngine.cpp - Channeled Audio output JACK
      5   Copyright (C) 2012-2012 Mark McCurry
      6   Author: Mark McCurry
      7 
      8   This program is free software; you can redistribute it and/or
      9   modify it under the terms of the GNU General Public License
     10   as published by the Free Software Foundation; either version 2
     11   of the License, or (at your option) any later version.
     12 */
     13 
     14 #include <jack/jack.h>
     15 #include <string>
     16 #include <cstring>
     17 #include <err.h>
     18 #include <cstdio>
     19 #include <cassert>
     20 
     21 #include "Nio.h"
     22 #include "Compressor.h"
     23 #include "../Misc/Util.h"
     24 #include "../Misc/Master.h"
     25 #include "../Misc/Part.h"
     26 #include "../Misc/MiddleWare.h"
     27 
     28 #include "JackMultiEngine.h"
     29 
     30 extern zyn::MiddleWare *middleware;
     31 extern char *instance_name;
     32 
     33 namespace zyn {
     34 
     35 using std::string;
     36 
     37 struct jack_multi
     38 {
     39     jack_port_t *ports[NUM_MIDI_PARTS * 2 + 2];
     40     float peaks[NUM_MIDI_PARTS + 1];
     41     jack_client_t *client;
     42     bool running;
     43 };
     44 
     45 JackMultiEngine::JackMultiEngine(const SYNTH_T &synth)
     46     :AudioOut(synth), impl(new jack_multi())
     47 {
     48     impl->running = false;
     49     impl->client  = NULL;
     50     memset(impl->peaks, 0, sizeof(impl->peaks));
     51 
     52     name = "JACK-MULTI";
     53 }
     54 
     55 JackMultiEngine::~JackMultiEngine(void)
     56 {
     57     delete impl;
     58 }
     59 
     60 void JackMultiEngine::setAudioEn(bool nval)
     61 {
     62     if(nval)
     63         Start();
     64     else
     65         Stop();
     66 }
     67 
     68 bool JackMultiEngine::getAudioEn() const
     69 {
     70     return impl->running;
     71 }
     72 
     73 
     74 
     75 bool JackMultiEngine::Start(void)
     76 {
     77     if(impl->client)
     78         return true;
     79 
     80     string clientname = "zynaddsubfx";
     81     string postfix    = Nio::getPostfix();
     82     if(!postfix.empty())
     83         clientname += "_" + postfix;
     84     if(Nio::pidInClientName)
     85         clientname += "_" + os_pid_as_padded_string();
     86     jack_status_t jackstatus;
     87 
     88     if(instance_name)
     89         impl->client = jack_client_open(instance_name, JackNullOption, &jackstatus);
     90     else
     91         impl->client = jack_client_open(clientname.c_str(), JackNullOption, &jackstatus);
     92 
     93     if(!impl->client)
     94         errx(1, "failed to connect to jack...");
     95 
     96 
     97     //Create the set of jack ports
     98     char portName[20];
     99     memset(portName,0,sizeof(portName));
    100 
    101 #define JACK_REGISTER(x) jack_port_register(impl->client, x, \
    102         JACK_DEFAULT_AUDIO_TYPE, JackPortIsOutput | JackPortIsTerminal, 0)
    103     //Create the master wet port
    104 
    105     impl->ports[0] = JACK_REGISTER("out-L");
    106     impl->ports[1] = JACK_REGISTER("out-R");
    107 
    108     //Create all part's outputs
    109     for(int i = 0; i < NUM_MIDI_PARTS * 2; i += 2) {
    110         snprintf(portName, 19, "part%d/out-L", i / 2);
    111         impl->ports[2 + i] = JACK_REGISTER(portName);
    112         snprintf(portName, 19, "part%d/out-R", i / 2);
    113         impl->ports[3 + i] = JACK_REGISTER(portName);
    114     }
    115 
    116     //verify that all sample rate and buffer_size are the same in jack.
    117     //This insures that the connection can be made with no resampling or
    118     //buffering
    119     if(synth.samplerate != jack_get_sample_rate(impl->client))
    120         errx(1, "jack must have the same sample rate!");
    121     if(synth.buffersize != (int) jack_get_buffer_size(impl->client))
    122         errx(1, "jack must have the same buffer size");
    123 
    124     jack_set_process_callback(impl->client, _processCallback, this);
    125 
    126     //run
    127     if(jack_activate(impl->client))
    128         errx(1, "failed at starting the jack client");
    129     impl->running = true;
    130     return true;
    131 }
    132 
    133 int JackMultiEngine::_processCallback(jack_nframes_t nframes, void *arg)
    134 {
    135     return static_cast<JackMultiEngine *>(arg)->processAudio(nframes);
    136 }
    137 
    138 int JackMultiEngine::processAudio(jack_nframes_t nframes)
    139 {
    140     //Gather all buffers
    141     float *buffers[NUM_MIDI_PARTS * 2 + 2];
    142 
    143     for(int i = 0; i < NUM_MIDI_PARTS * 2 + 2; ++i) {
    144         //Abort if ports are only partially initialized
    145         if(!impl->ports[i])
    146             return false;
    147 
    148         buffers[i] =
    149             (float *)jack_port_get_buffer(impl->ports[i], nframes);
    150         assert(buffers[i]);
    151     }
    152 
    153     //Get the wet samples from OutMgr
    154     Stereo<float *> smp = getNext();
    155     memcpy(buffers[0], smp.l, synth.bufferbytes);
    156     memcpy(buffers[1], smp.r, synth.bufferbytes);
    157 
    158     const int maxFrames = (synth.bufferbytes / sizeof(float));
    159 
    160     //Make sure the audio output doesn't overflow
    161     if(isOutputCompressionEnabled)
    162         for(int frame = 0; frame != maxFrames; ++frame) {
    163             float &p = impl->peaks[0];
    164             float &l = buffers[0][frame];
    165             float &r = buffers[1][frame];
    166             stereoCompressor(synth.samplerate, p, l, r);
    167         }
    168 
    169     //Gather other samples from individual parts
    170     Master &master = *middleware->spawnMaster();
    171     for(int i = 0; i < NUM_MIDI_PARTS; ++i) {
    172         float &p = impl->peaks[i + 1];
    173 
    174         memcpy(buffers[2*i + 2], master.part[i]->partoutl, synth.bufferbytes);
    175         memcpy(buffers[2*i + 3], master.part[i]->partoutr, synth.bufferbytes);
    176 
    177         //Make sure the audio output doesn't overflow
    178         if(isOutputCompressionEnabled)
    179             for(int frame = 0; frame != maxFrames; ++frame) {
    180                 float &l = buffers[2*i + 2][frame];
    181                 float &r = buffers[2*i + 3][frame];
    182                 stereoCompressor(synth.samplerate, p, l, r);
    183             }
    184     }
    185 
    186     return false;
    187 }
    188 
    189 void JackMultiEngine::Stop()
    190 {
    191     for(int i = 0; i < NUM_MIDI_PARTS * 2 + 2; ++i) {
    192         jack_port_t *port = impl->ports[i];
    193         impl->ports[i] = NULL;
    194         if(port)
    195             jack_port_unregister(impl->client, port);
    196     }
    197 
    198     if(impl->client)
    199         jack_client_close(impl->client);
    200     impl->client = NULL;
    201 
    202     impl->running = false;
    203 }
    204 
    205 }