[yoshimi-user] Separate Jack Audio Outputs patch - GIT PATCH

  • From: Дерябин Андрей <andrewderyabin@xxxxxxxxx>
  • To: yoshimi-user@xxxxxxxxxxxxxxxxxxxxx
  • Date: Sat, 06 Apr 2013 08:34:36 +0000

Hi All!

Here is my final patch for multiple per-channel outputs in yoshimi jack engine.

Summary:

1. Added 2 mono outputs per channel (ch_x_l and ch_x_r).
2. Added 2 mono outputs for mix of all channels with all system effects applyed (mix_l and mix_r). They work exactly the same way as left and right outputs in current stereo version.

System effects only in effect with mixed outputs due to their stereo nature in initial source code.

P.S. At the beginning I simply wanted to write a song, but ended up with making a patch :-D

From 370eaae08e620a73cb685992edfd3e6d184f9967 Mon Sep 17 00:00:00 2001
From: Andrew Deryabin <andrewderyabin@xxxxxxxxx>
Date: Sat, 6 Apr 2013 11:58:10 +0400
Subject: [PATCH 1/1] Add support for multiple jack outputs

---
src/Misc/SynthEngine.cpp | 100 ++++++++++++++++++++++++++++++---------------
src/Misc/SynthEngine.h | 2 +-
src/MusicIO/JackEngine.cpp | 61 ++++++++++++++++++++-------
src/MusicIO/JackEngine.h | 4 +-
src/MusicIO/MusicIO.cpp | 95 +++++++++++++++++++++++++-----------------
src/MusicIO/MusicIO.h | 4 +-
6 files changed, 174 insertions(+), 92 deletions(-)

diff --git a/src/Misc/SynthEngine.cpp b/src/Misc/SynthEngine.cpp
index 5bfb064..5f063c4 100644
--- a/src/Misc/SynthEngine.cpp
+++ b/src/Misc/SynthEngine.cpp
@@ -357,22 +357,26 @@ void SynthEngine::partonoff(int npart, int what)


// Master audio out (the final sound)
-void SynthEngine::MasterAudio(float *outl, float *outr)
+void SynthEngine::MasterAudio(float *outl [NUM_MIDI_PARTS], float *outr
[NUM_MIDI_PARTS])
{
- memset(outl, 0, bufferbytes);
- memset(outr, 0, bufferbytes);
+ int npart;
+ for (npart = 0; npart < NUM_MIDI_PARTS; ++npart)
+ {
+ memset(outl[npart], 0, bufferbytes);
+ memset(outr[npart], 0, bufferbytes);
+ }
if (isMuted())
return;

actionLock(lock);

- // Compute part samples and store them npart]->partoutl,partoutr
- int npart;
+ // Compute part samples and store them ->partoutl,partoutr
for (npart = 0; npart < NUM_MIDI_PARTS; ++npart)
- if (part[npart]->Penabled)
- {
- part[npart]->ComputePartSmps();
- }
+ if (part[npart]->Penabled)
+ {
+ part[npart]->ComputePartSmps();
+ }
+
// Insertion effects
int nefx;
for (nefx = 0; nefx < NUM_INS_EFX; ++nefx)
@@ -387,6 +391,7 @@ void SynthEngine::MasterAudio(float *outl, float *outr)
}
}

+
// Apply the part volumes and pannings (after insertion effects)
for (npart = 0; npart < NUM_MIDI_PARTS; ++npart)
{
@@ -397,15 +402,12 @@ void SynthEngine::MasterAudio(float *outl, float *outr)
float oldvol_r = part[npart]->oldvolumer;
float newvol_l = part[npart]->pannedVolLeft();
float newvol_r = part[npart]->pannedVolRight();
- if (aboveAmplitudeThreshold(oldvol_l, newvol_l)
- || aboveAmplitudeThreshold(oldvol_r, newvol_r))
+ if (aboveAmplitudeThreshold(oldvol_l, newvol_l) ||
aboveAmplitudeThreshold(oldvol_r, newvol_r))
{ // the volume or the panning has changed and needs interpolation
for (int i = 0; i < buffersize; ++i)
{
- float vol_l = interpolateAmplitude(oldvol_l, newvol_l, i,
- buffersize);
- float vol_r = interpolateAmplitude(oldvol_r, newvol_r, i,
- buffersize);
+ float vol_l = interpolateAmplitude(oldvol_l, newvol_l, i,
buffersize);
+ float vol_r = interpolateAmplitude(oldvol_r, newvol_r, i,
buffersize);
part[npart]->partoutl[i] *= vol_l;
part[npart]->partoutr[i] *= vol_r;
}
@@ -466,18 +468,29 @@ void SynthEngine::MasterAudio(float *outl, float *outr)
float outvol = sysefx[nefx]->sysefxgetvolume();
for (int i = 0; i < buffersize; ++i)
{
- outl[i] += tmpmixl[i] * outvol;
- outr[i] += tmpmixr[i] * outvol;
+ outl[NUM_MIDI_PARTS][i] += tmpmixl[i] * outvol;
+ outr[NUM_MIDI_PARTS][i] += tmpmixr[i] * outvol;
+ }
+ }
+
+
+ // Copy all parts
+ for (npart = 0; npart < NUM_MIDI_PARTS; ++npart)
+ {
+ for (int i = 0; i < buffersize; ++i)
+ {
+ outl[npart][i] = part[npart]->partoutl[i];
+ outr[npart][i] = part[npart]->partoutr[i];
}
}

- // Mix all parts
+ // Mix all parts to mixed outputs
for (npart = 0; npart < NUM_MIDI_PARTS; ++npart)
{
for (int i = 0; i < buffersize; ++i)
{ // the volume did not change
- outl[i] += part[npart]->partoutl[i];
- outr[i] += part[npart]->partoutr[i];
+ outl[NUM_MIDI_PARTS][i] += outl[npart][i];
+ outr[NUM_MIDI_PARTS][i] += outr[npart][i];
}
}

@@ -486,7 +499,7 @@ void SynthEngine::MasterAudio(float *outl, float *outr)
{
if (Pinsparts[nefx] == -2)
{
- insefx[nefx]->out(outl, outr);
+ insefx[nefx]->out(outl[NUM_MIDI_PARTS], outr[NUM_MIDI_PARTS]);
}
}

@@ -501,34 +514,53 @@ void SynthEngine::MasterAudio(float *outl, float *outr)
vurmspeakr = 1e-12f;
vupeakLock(unlock);

+
float absval;
+ //Per output master volume and fade
+ for (npart = 0; npart < NUM_MIDI_PARTS; ++npart)
+ {
+ for (int idx = 0; idx < buffersize; ++idx)
+ {
+ outl[npart][idx] *= volume; // apply Master Volume
+ outr[npart][idx] *= volume;
+
+ if (shutup) // fade-out
+ {
+ float fade = (float) (buffersize - idx) / (float) buffersize;
+ outl[npart][idx] *= fade;
+ outr[npart][idx] *= fade;
+ }
+ }
+ }
+
+ //Master volume and clip calculation for mixed outputs
for (int idx = 0; idx < buffersize; ++idx)
{
- outl[idx] *= volume; // apply Master Volume
- outr[idx] *= volume;
+ outl[NUM_MIDI_PARTS][idx] *= volume; // apply Master Volume
+ outr[NUM_MIDI_PARTS][idx] *= volume;

- if ((absval = fabsf(outl[idx])) > vuoutpeakl) // Peak computation (for
vumeters)
+ if ((absval = fabsf(outl[NUM_MIDI_PARTS][idx])) > vuoutpeakl) // Peak
computation (for vumeters)
vuoutpeakl = absval;
- if ((absval = fabsf(outr[idx])) > vuoutpeakr)
+ if ((absval = fabsf(outr[NUM_MIDI_PARTS][idx])) > vuoutpeakr)
vuoutpeakr = absval;
- vurmspeakl += outl[idx] * outl[idx]; // RMS Peak
- vurmspeakr += outr[idx] * outr[idx];
+ vurmspeakl += outl[NUM_MIDI_PARTS][idx] * outl[NUM_MIDI_PARTS][idx];
// RMS Peak
+ vurmspeakr += outr[NUM_MIDI_PARTS][idx] * outr[NUM_MIDI_PARTS][idx];

// check for clips
- if (outl[idx] > 1.0f)
+ if (outl[NUM_MIDI_PARTS][idx] > 1.0f)
clippedL = true;
- else if (outl[idx] < -1.0f)
+ else if (outl[NUM_MIDI_PARTS][idx] < -1.0f)
clippedL = true;
- if (outr[idx] > 1.0f)
+ if (outr[NUM_MIDI_PARTS][idx] > 1.0f)
clippedR = true;
- else if (outr[idx] < -1.0f)
+ else if (outr[NUM_MIDI_PARTS][idx] < -1.0f)
clippedR = true;

if (shutup) // fade-out
{
- float fade = (float)(buffersize - idx) / (float)buffersize;
- outl[idx] *= fade;
- outr[idx] *= fade;
+ float fade = (float) (buffersize - idx) / (float) buffersize;
+ outl[NUM_MIDI_PARTS][idx] *= fade;
+ outr[NUM_MIDI_PARTS][idx] *= fade;
}
}
if (shutup)
diff --git a/src/Misc/SynthEngine.h b/src/Misc/SynthEngine.h
index d8f5700..168ed8b 100644
--- a/src/Misc/SynthEngine.h
+++ b/src/Misc/SynthEngine.h
@@ -70,7 +70,7 @@ class SynthEngine : private SynthHelper, MiscFuncs
float numRandom(void);
unsigned int random(void);
void ShutUp(void);
- void MasterAudio(float *outl, float *outr);
+ void MasterAudio(float *outl [NUM_MIDI_PARTS], float *outr
[NUM_MIDI_PARTS]);
void partonoff(int npart, int what);
void Mute(void) { __sync_or_and_fetch(&muted, 0xFF); }
void Unmute(void) { __sync_and_and_fetch(&muted, 0); }
diff --git a/src/MusicIO/JackEngine.cpp b/src/MusicIO/JackEngine.cpp
index 5eba968..48dc40d 100644
--- a/src/MusicIO/JackEngine.cpp
+++ b/src/MusicIO/JackEngine.cpp
@@ -23,6 +23,7 @@
#include <jack/thread.h>
#include <fcntl.h>
#include <sys/stat.h>
+#include <sstream>

using namespace std;

@@ -33,7 +34,7 @@ JackEngine::JackEngine() : jackClient(NULL)
{
audio.jackSamplerate = 0;
audio.jackNframes = 0;
- for (int i = 0; i < 2; ++i)
+ for (int i = 0; i < (2*NUM_MIDI_PARTS+2); ++i)
{
audio.ports[i] = NULL;
audio.portBuffs[i] = NULL;
@@ -116,6 +117,7 @@ bool JackEngine::openJackClient(string server)

bool JackEngine::Start(void)
{
+ bool jackPortsRegistered = true;
jack_set_error_function(_errorCallback);
jack_set_xrun_callback(jackClient, _xrunCallback, this);
#if defined(JACK_SESSION)
@@ -142,9 +144,16 @@ bool JackEngine::Start(void)
goto bail_out;
}

- if (!jack_activate(jackClient)
- && NULL != audio.ports[0]
- && NULL != audio.ports[1])
+ for (int port = 0; port < (2 * NUM_MIDI_PARTS + 2); ++port)
+ {
+ if (!audio.ports[port])
+ {
+ jackPortsRegistered = false;
+ break;
+ }
+ }
+
+ if (!jack_activate(jackClient) && jackPortsRegistered)
{
if (!Runtime.restoreJackSession && Runtime.connectJackaudio &&
!connectJackPorts())
{
@@ -170,7 +179,7 @@ void JackEngine::Close(void)
if (NULL != jackClient)
{
int chk;
- for (int chan = 0; chan < 2; ++chan)
+ for (int chan = 0; chan < (2*NUM_MIDI_PARTS+2); ++chan)
{
if (NULL != audio.ports[chan])
jack_port_unregister(jackClient, audio.ports[chan]);
@@ -197,12 +206,28 @@ void JackEngine::Close(void)

bool JackEngine::openAudio(void)
{
- const char *portnames[] = { "left", "right" };
- for (int port = 0; port < 2; ++port)
- audio.ports[port] = jack_port_register(jackClient, portnames[port],
- JACK_DEFAULT_AUDIO_TYPE,
- JackPortIsOutput, 0);
- if (audio.ports[0] && audio.ports[1])
+ for (int port = 0; port < 2 * NUM_MIDI_PARTS; ++port)
+ {
+ stringstream portName;
+ portName << "ch" << ((port / 2) + 1) << ((port % 2) ? "_r" : "_l");
+ audio.ports[port] = jack_port_register(jackClient,
portName.str().c_str(), JACK_DEFAULT_AUDIO_TYPE, JackPortIsOutput, 0);
+ }
+
+ //Register mixer outputs for all channels
+ audio.ports[2 * NUM_MIDI_PARTS] = jack_port_register(jackClient, "mix_l",
JACK_DEFAULT_AUDIO_TYPE, JackPortIsOutput, 0);
+ audio.ports[2 * NUM_MIDI_PARTS + 1] = jack_port_register(jackClient,
"mix_r", JACK_DEFAULT_AUDIO_TYPE, JackPortIsOutput, 0);
+
+ bool jackPortsRegistered = true;
+ for (int port = 0; port < (2 * NUM_MIDI_PARTS + 2); ++port)
+ {
+ if (!audio.ports[port])
+ {
+ jackPortsRegistered = false;
+ break;
+ }
+ }
+
+ if (jackPortsRegistered)
return prepBuffers(false) && latencyPrep();
else
Runtime.Log("Failed to register jack audio ports");
@@ -242,7 +267,7 @@ bool JackEngine::connectJackPorts(void)
return false;
}
int ret;
- for (int port = 0; port < 2 && NULL != audio.ports[port]; ++port)
+ for (int port = 0; (port < (2 * NUM_MIDI_PARTS)) && (NULL !=
audio.ports[port]); ++port)
{
const char *port_name = jack_port_name(audio.ports[port]);
if ((ret = jack_connect(jackClient, port_name, playback_ports[port])))
@@ -297,7 +322,7 @@ int JackEngine::processCallback(jack_nframes_t nframes)

bool JackEngine::processAudio(jack_nframes_t nframes)
{
- for (int port = 0; port < 2; ++port)
+ for (int port = 0; port < (2*NUM_MIDI_PARTS+2); ++port)
{
audio.portBuffs[port] =
(float*)jack_port_get_buffer(audio.ports[port], nframes);
@@ -308,8 +333,14 @@ bool JackEngine::processAudio(jack_nframes_t nframes)
}
}
getAudio();
- memcpy(audio.portBuffs[0], zynLeft, sizeof(float) * nframes);
- memcpy(audio.portBuffs[1], zynRight, sizeof(float) * nframes);
+ for (int port = 0; port < NUM_MIDI_PARTS; ++port)
+ {
+ memcpy(audio.portBuffs[port * 2], zynLeft[port], sizeof(float) *
nframes);
+ memcpy(audio.portBuffs[port * 2 + 1], zynRight[port], sizeof(float) *
nframes);
+ }
+ //And mixed outputs
+ memcpy(audio.portBuffs[2 * NUM_MIDI_PARTS], zynLeft[NUM_MIDI_PARTS],
sizeof(float) * nframes);
+ memcpy(audio.portBuffs[2 * NUM_MIDI_PARTS + 1], zynRight[NUM_MIDI_PARTS],
sizeof(float) * nframes);
return true;
}

diff --git a/src/MusicIO/JackEngine.h b/src/MusicIO/JackEngine.h
index b43632b..5b55671 100644
--- a/src/MusicIO/JackEngine.h
+++ b/src/MusicIO/JackEngine.h
@@ -79,8 +79,8 @@ class JackEngine : public MusicIO
struct {
unsigned int jackSamplerate;
unsigned int jackNframes;
- jack_port_t *ports[2];
- float *portBuffs[2];
+ jack_port_t *ports[2*NUM_MIDI_PARTS+2];
+ float *portBuffs[2*NUM_MIDI_PARTS+2];
} audio;

struct {
diff --git a/src/MusicIO/MusicIO.cpp b/src/MusicIO/MusicIO.cpp
index 926e22e..1fc5b68 100644
--- a/src/MusicIO/MusicIO.cpp
+++ b/src/MusicIO/MusicIO.cpp
@@ -29,18 +29,28 @@ using namespace std;
#include "MusicIO/MusicIO.h"

MusicIO::MusicIO() :
- zynLeft(NULL),
- zynRight(NULL),
interleavedShorts(NULL),
rtprio(25)
-{ }
+{
+ memset(zynLeft, 0, sizeof(float) * (NUM_MIDI_PARTS+1));
+ memset(zynRight, 0, sizeof(float) * (NUM_MIDI_PARTS+1));
+}

MusicIO::~MusicIO()
{
- if (zynLeft)
- fftwf_free(zynLeft);
- if (zynRight)
- fftwf_free(zynRight);
+ for (int npart = 0; npart < (NUM_MIDI_PARTS+1); ++npart)
+ {
+ if (zynLeft[npart])
+ {
+ fftwf_free(zynLeft[npart]);
+ zynLeft[npart] = NULL;
+ }
+ if (zynRight[npart])
+ {
+ fftwf_free(zynRight[npart]);
+ zynRight[npart] = NULL;
+ }
+ }
if (interleavedShorts)
delete [] interleavedShorts;
}
@@ -51,13 +61,13 @@ void MusicIO::InterleaveShorts(void)
int buffersize = getBuffersize();
int idx = 0;
double scaled;
- for (int frame = 0; frame < buffersize; ++frame)
- { // with a grateful nod to libsamplerate ...
- scaled = zynLeft[frame] * (8.0 * 0x10000000);
- interleavedShorts[idx++] = (short int)(lrint(scaled) >> 16);
- scaled = zynRight[frame] * (8.0 * 0x10000000);
- interleavedShorts[idx++] = (short int)(lrint(scaled) >> 16);
- }
+ for (int frame = 0; frame < buffersize; ++frame)
+ { // with a grateful nod to libsamplerate ...
+ scaled = zynLeft[NUM_MIDI_PARTS][frame] * (8.0 * 0x10000000);
+ interleavedShorts[idx++] = (short int) (lrint(scaled) >> 16);
+ scaled = zynRight[NUM_MIDI_PARTS][frame] * (8.0 * 0x10000000);
+ interleavedShorts[idx++] = (short int) (lrint(scaled) >> 16);
+ }
}


@@ -143,34 +153,43 @@ bool MusicIO::prepBuffers(bool with_interleaved)
int buffersize = getBuffersize();
if (buffersize > 0)
{
- if (!(zynLeft = (float*)fftwf_malloc(buffersize * sizeof(float))))
- goto bail_out;
- if (!(zynRight = (float*)fftwf_malloc(buffersize * sizeof(float))))
- goto bail_out;
- memset(zynLeft, 0, buffersize * sizeof(float));
- memset(zynRight, 0, buffersize * sizeof(float));
- if (with_interleaved)
- {
- interleavedShorts = new short int[buffersize * 2];
- if (NULL == interleavedShorts)
- goto bail_out;
- memset(interleavedShorts, 0, sizeof(short int) * buffersize * 2);
- }
- return true;
+ for (int part = 0; part < (NUM_MIDI_PARTS+1); part++)
+ {
+ if (!(zynLeft [part] = (float*) fftwf_malloc(
+ buffersize * sizeof(float))))
+ goto bail_out;
+ if (!(zynRight [part] = (float*) fftwf_malloc(
+ buffersize * sizeof(float))))
+ goto bail_out;
+ memset(zynLeft [part], 0, buffersize * sizeof(float));
+ memset(zynRight [part], 0, buffersize * sizeof(float));
+
+ }
+ if (with_interleaved)
+ {
+ interleavedShorts = new short int[buffersize * 2];
+ if (NULL == interleavedShorts)
+ goto bail_out;
+ memset(interleavedShorts, 0, sizeof(short int) *
buffersize * 2);
+ }
+ return true;
}

bail_out:
Runtime.Log("Failed to allocate audio buffers, size " +
asString(buffersize));
- if (zynLeft)
- {
- fftwf_free(zynLeft);
- zynLeft = NULL;
- }
- if (zynRight)
- {
- fftwf_free(zynRight);
- zynRight = NULL;
- }
+ for (int part = 0; part < (NUM_MIDI_PARTS+1); part++)
+ {
+ if (zynLeft [part])
+ {
+ fftwf_free(zynLeft [part]);
+ zynLeft [part] = NULL;
+ }
+ if (zynRight [part])
+ {
+ fftwf_free(zynRight [part]);
+ zynRight [part] = NULL;
+ }
+ }
if (interleavedShorts)
{
delete [] interleavedShorts;
diff --git a/src/MusicIO/MusicIO.h b/src/MusicIO/MusicIO.h
index b8facf8..6c8471d 100644
--- a/src/MusicIO/MusicIO.h
+++ b/src/MusicIO/MusicIO.h
@@ -42,8 +42,8 @@ class MusicIO : virtual protected MiscFuncs
void setMidiNote(unsigned char chan, unsigned char note);
void setMidiNote(unsigned char chan, unsigned char note, unsigned char
velocity);

- float *zynLeft;
- float *zynRight;
+ float *zynLeft [NUM_MIDI_PARTS + 1];
+ float *zynRight [NUM_MIDI_PARTS + 1];
short int *interleavedShorts;
int rtprio;
};
--
1.8.2

Other related posts:

  • » [yoshimi-user] Separate Jack Audio Outputs patch - GIT PATCH - Дерябин Андрей