[yoshimi-user] Patch for Separate Jack Audio Outputs for every channel (patch file included)

  • From: Дерябин Андрей <andrewderyabin@xxxxxxxxx>
  • To: yoshimi-user@xxxxxxxxxxxxxxxxxxxxx
  • Date: Thu, 04 Apr 2013 18:27:30 +0000

Hello!

Thank you, Jeremi, for the link, but I was unable to build the code from that git repo. May be it's in the imtermidiate state now, don't know.
Anyway, I'm posting my patch - it's working out of the box :)


04.04.2013 13:38, Jeremy Jongepier пишет:

On 04/04/2013 07:22 PM, Дерябин Андрей wrote:
Hello all!

I' ve started using yoshimi several days ago (thanks to authors -
it's performance is excellent!) with ardour-3. All was ok (midi channel
mapping, jack session support), until I decided to make different
effects on every instrument. It was not possible due to only one stereo
output, that simply mixes all 16 channels. So I've modified yoshimi code
and made a patch to make every channel appear as separate stereo output
in jack. Now it works almost exellent for me - I can route every channel
to dedicated ardour bus!
If it is possible to include my modifications in main code (if
somebody else needs it :) ), I can send a patch!

P.S. I had to disable system efx because of it stereo-only nature. Ather
effects (channel inserts, etc) works ok!

PPS Sorry for my english :-)

Hello Andrew,

Patches are always welcome so if you'd like to send a patch, thanks in
advance. Regarding the functionality itself, you're not the first one
who has been working on this: https://gitorious.org/small-hacks/yoshimi

Regards,

Jeremy


------------------------------------------------------------------------------
Minimize network downtime and maximize team effectiveness.
Reduce network management and security costs.Learn how to hire
the most talented Cisco Certified professionals. Visit the
Employer Resources Portal
http://www.cisco.com/web/learning/employer_resources/index.html
_______________________________________________
yoshimi-user mailing list
yoshimi-user@xxxxxxxxxxxxxxxxxxxxx
https://lists.sourceforge.net/lists/listinfo/yoshimi-user

diff -rupN original/src/Effects/EffectMgr.cpp new/src/Effects/EffectMgr.cpp
--- original/src/Effects/EffectMgr.cpp 2012-07-02 21:20:36.000000000 +0000
+++ new/src/Effects/EffectMgr.cpp 2013-04-03 22:31:11.000000000 +0000
@@ -182,8 +182,8 @@ void EffectMgr::out(float *smpsl, float
{
if (!insertion)
{
- memset(smpsl, 0, synth->bufferbytes);
- memset(smpsr, 0, synth->bufferbytes);
+ memset(smpsl, 0, synth->bufferbytes);
+ memset(smpsr, 0, synth->bufferbytes);
memset(efxoutl, 0, synth->bufferbytes);
memset(efxoutr, 0, synth->bufferbytes);
}
diff -rupN original/src/Misc/SynthEngine.cpp new/src/Misc/SynthEngine.cpp
--- original/src/Misc/SynthEngine.cpp 2012-07-02 21:20:36.000000000 +0000
+++ new/src/Misc/SynthEngine.cpp 2013-04-03 22:33:12.000000000 +0000
@@ -357,15 +357,19 @@ void SynthEngine::partonoff(int npart, i


// 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;

// Compute part samples and store them npart]->partoutl,partoutr
- int npart;
+
for (npart = 0; npart < NUM_MIDI_PARTS; ++npart)
if (part[npart]->Penabled)
{
@@ -423,70 +427,72 @@ void SynthEngine::MasterAudio(float *out
}
}
}
- // System effects
- for (nefx = 0; nefx < NUM_SYS_EFX; ++nefx)
- {
- if (!sysefx[nefx]->geteffect())
- continue; // is disabled
-
- // Clean up the samples used by the system effects
- memset(tmpmixl, 0, bufferbytes);
- memset(tmpmixr, 0, bufferbytes);
-
- // Mix the channels according to the part settings about System Effect
- for (npart = 0; npart < NUM_MIDI_PARTS; ++npart)
- {
- // skip if part is disabled or has no output to effect
- if (part[npart]->Penabled && Psysefxvol[nefx][npart])
- {
- // the output volume of each part to system effect
- float vol = sysefxvol[nefx][npart];
- for (int i = 0; i < buffersize; ++i)
- {
- actionLock(lock);
- tmpmixl[i] += part[npart]->partoutl[i] * vol;
- tmpmixr[i] += part[npart]->partoutr[i] * vol;
- actionLock(unlock);
- }
- }
- }

- // system effect send to next ones
- for (int nefxfrom = 0; nefxfrom < nefx; ++nefxfrom)
- {
- if (Psysefxsend[nefxfrom][nefx])
- {
- float v = sysefxsend[nefxfrom][nefx];
- for (int i = 0; i < buffersize; ++i)
- {
- actionLock(lock);
- tmpmixl[i] += sysefx[nefxfrom]->efxoutl[i] * v;
- tmpmixr[i] += sysefx[nefxfrom]->efxoutr[i] * v;
- actionLock(unlock);
- }
- }
- }
- sysefx[nefx]->out(tmpmixl, tmpmixr);
-
- // Add the System Effect to sound output
- float outvol = sysefx[nefx]->sysefxgetvolume();
- for (int i = 0; i < buffersize; ++i)
- {
- actionLock(lock);
- outl[i] += tmpmixl[i] * outvol;
- outr[i] += tmpmixr[i] * outvol;
- actionLock(unlock);
- }
- }
+ //TODO FIXME System effects are disabled since they were programmed for
stereo mix only
+// // System effects
+// for (nefx = 0; nefx < NUM_SYS_EFX; ++nefx)
+// {
+// if (!sysefx[nefx]->geteffect())
+// continue; // is disabled
+//
+// // Clean up the samples used by the system effects
+// memset(tmpmixl, 0, bufferbytes);
+// memset(tmpmixr, 0, bufferbytes);
+//
+// // Mix the channels according to the part settings about System
Effect
+// for (npart = 0; npart < NUM_MIDI_PARTS; ++npart)
+// {
+// // skip if part is disabled or has no output to effect
+// if (part[npart]->Penabled && Psysefxvol[nefx][npart])
+// {
+// // the output volume of each part to system effect
+// float vol = sysefxvol[nefx][npart];
+// for (int i = 0; i < buffersize; ++i)
+// {
+// actionLock(lock);
+// tmpmixl[i] += part[npart]->partoutl[i] * vol;
+// tmpmixr[i] += part[npart]->partoutr[i] * vol;
+// actionLock(unlock);
+// }
+// }
+// }
+//
+// // system effect send to next ones
+// for (int nefxfrom = 0; nefxfrom < nefx; ++nefxfrom)
+// {
+// if (Psysefxsend[nefxfrom][nefx])
+// {
+// float v = sysefxsend[nefxfrom][nefx];
+// for (int i = 0; i < buffersize; ++i)
+// {
+// actionLock(lock);
+// tmpmixl[i] += sysefx[nefxfrom]->efxoutl[i] * v;
+// tmpmixr[i] += sysefx[nefxfrom]->efxoutr[i] * v;
+// actionLock(unlock);
+// }
+// }
+// }
+// sysefx[nefx]->out(tmpmixl, tmpmixr);
+//
+// // Add the System Effect to sound output
+// float outvol = sysefx[nefx]->sysefxgetvolume();
+// for (int i = 0; i < buffersize; ++i)
+// {
+// actionLock(lock);
+// outl[i] += tmpmixl[i] * outvol;
+// outr[i] += tmpmixr[i] * outvol;
+// actionLock(unlock);
+// }
+// }

- // Mix all parts
+ // Copy all parts
for (npart = 0; npart < NUM_MIDI_PARTS; ++npart)
{
for (int i = 0; i < buffersize; ++i)
{ // the volume did not change
actionLock(lock);
- outl[i] += part[npart]->partoutl[i];
- outr[i] += part[npart]->partoutr[i];
+ outl[npart][i] += part[npart]->partoutl[i];
+ outr[npart][i] += part[npart]->partoutr[i];
actionLock(unlock);
}
}
@@ -497,7 +503,11 @@ void SynthEngine::MasterAudio(float *out
if (Pinsparts[nefx] == -2)
{
actionLock(lock);
- insefx[nefx]->out(outl, outr);
+ for (npart = 0; npart < NUM_MIDI_PARTS; ++npart)
+ {
+ insefx[nefx]->out(outl[npart], outr[npart]);
+ }
+
actionLock(unlock);
}
}
@@ -512,35 +522,40 @@ void SynthEngine::MasterAudio(float *out
vupeakLock(unlock);

float absval;
- for (int idx = 0; idx < buffersize; ++idx)
- {
- outl[idx] *= volume; // apply Master Volume
- outr[idx] *= volume;
-
- if ((absval = fabsf(outl[idx])) > vuoutpeakl) // Peak computation (for
vumeters)
- vuoutpeakl = absval;
- if ((absval = fabsf(outr[idx])) > vuoutpeakr)
- vuoutpeakr = absval;
- vurmspeakl += outl[idx] * outl[idx]; // RMS Peak
- vurmspeakr += outr[idx] * outr[idx];
-
- // check for clips
- if (outl[idx] > 1.0f)
- clippedL = true;
- else if (outl[idx] < -1.0f)
- clippedL = true;
- if (outr[idx] > 1.0f)
- clippedR = true;
- else if (outr[idx] < -1.0f)
- clippedR = true;
-
- if (shutup) // fade-out
- {
- float fade = (float)(buffersize - idx) / (float)buffersize;
- outl[idx] *= fade;
- outr[idx] *= 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 ((absval = fabsf(outl[npart][idx])) > vuoutpeakl) //
Peak computation (for vumeters)
+ vuoutpeakl = absval;
+ if ((absval = fabsf(outr[npart][idx])) > vuoutpeakr)
+ vuoutpeakr = absval;
+ vurmspeakl += outl[npart][idx] * outl[npart][idx]; //
RMS Peak
+ vurmspeakr += outr[npart][idx] * outr[npart][idx];
+
+ // check for clips
+ //FIXME TODO clip calculation is wrong for separate
outputs! (don't want to fix it though..)
+ //Commenting them out
+ /*if (outl[npart][idx] > 1.0f)
+ clippedL = true;
+ else if (outl[npart][idx] < -1.0f)
+ clippedL = true;
+ if (outr[npart][idx] > 1.0f)
+ clippedR = true;
+ else if (outr[npart][idx] < -1.0f)
+ clippedR = true;*/
+
+ if (shutup) // fade-out
+ {
+ float fade = (float) (buffersize - idx) /
(float) buffersize;
+ outl[npart][idx] *= fade;
+ outr[npart][idx] *= fade;
+ }
+ }
+ }
if (shutup)
ShutUp();

diff -rupN original/src/Misc/SynthEngine.h new/src/Misc/SynthEngine.h
--- original/src/Misc/SynthEngine.h 2012-07-02 21:20:36.000000000 +0000
+++ new/src/Misc/SynthEngine.h 2013-04-03 22:26:12.000000000 +0000
@@ -70,7 +70,7 @@ class SynthEngine : private SynthHelper,
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 -rupN original/src/MusicIO/JackEngine.cpp new/src/MusicIO/JackEngine.cpp
--- original/src/MusicIO/JackEngine.cpp 2012-07-02 21:20:36.000000000 +0000
+++ new/src/MusicIO/JackEngine.cpp 2013-04-03 22:40:39.000000000 +0000
@@ -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(NU
{
audio.jackSamplerate = 0;
audio.jackNframes = 0;
- for (int i = 0; i < 2; ++i)
+ for (int i = 0; i < 2 * NUM_MIDI_PARTS; ++i)
{
audio.ports[i] = NULL;
audio.portBuffs[i] = NULL;
@@ -170,7 +171,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; ++chan)
{
if (NULL != audio.ports[chan])
jack_port_unregister(jackClient, audio.ports[chan]);
@@ -197,12 +198,25 @@ 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],
+ 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);
- if (audio.ports[0] && audio.ports[1])
+ }
+ bool jackPortsRegistered = true;
+ for (int port = 0; port < 2 * NUM_MIDI_PARTS; ++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 +256,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 +311,7 @@ int JackEngine::processCallback(jack_nfr

bool JackEngine::processAudio(jack_nframes_t nframes)
{
- for (int port = 0; port < 2; ++port)
+ for (int port = 0; port < (2 * NUM_MIDI_PARTS); ++port)
{
audio.portBuffs[port] =
(float*)jack_port_get_buffer(audio.ports[port], nframes);
@@ -307,11 +321,14 @@ bool JackEngine::processAudio(jack_nfram
return false;
}
}
- memset(audio.portBuffs[0], 0, sizeof(float) * nframes);
- memset(audio.portBuffs[1], 0, sizeof(float) * nframes);
+ //memset(audio.portBuffs[0], 0, sizeof(float) * nframes); <-- not necessary
+ //memset(audio.portBuffs[1], 0, sizeof(float) * nframes); <-- not necessary
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);
+ }
return true;
}

diff -rupN original/src/MusicIO/JackEngine.h new/src/MusicIO/JackEngine.h
--- original/src/MusicIO/JackEngine.h 2012-07-02 21:20:36.000000000 +0000
+++ new/src/MusicIO/JackEngine.h 2013-04-03 21:05:36.000000000 +0000
@@ -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];
+ float *portBuffs[2 * NUM_MIDI_PARTS];
} audio;

struct {
diff -rupN original/src/MusicIO/MusicIO.cpp new/src/MusicIO/MusicIO.cpp
--- original/src/MusicIO/MusicIO.cpp 2012-07-02 21:20:36.000000000 +0000
+++ new/src/MusicIO/MusicIO.cpp 2013-04-03 22:34:51.000000000 +0000
@@ -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);
+ memset(zynRight, 0, sizeof(float) * NUM_MIDI_PARTS);
+}

MusicIO::~MusicIO()
{
- if (zynLeft)
- fftwf_free(zynLeft);
- if (zynRight)
- fftwf_free(zynRight);
+ for (int npart = 0; npart < NUM_MIDI_PARTS; ++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,16 @@ 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 npart = 0; npart < NUM_MIDI_PARTS; ++npart)
+ {
+ for (int frame = 0; frame < buffersize; ++frame)
+ { // with a grateful nod to libsamplerate ...
+ scaled = zynLeft[npart][frame] * (8.0 * 0x10000000);
+ interleavedShorts[idx++] = (short int) (lrint(scaled)
16);
+ scaled = zynRight[npart][frame] * (8.0 * 0x10000000);
+ interleavedShorts[idx++] = (short int) (lrint(scaled)
16);
+ }
+ }
}


@@ -143,34 +156,43 @@ bool MusicIO::prepBuffers(bool with_inte
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; 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 *
NUM_MIDI_PARTS];
+ if (NULL == interleavedShorts)
+ goto bail_out;
+ memset(interleavedShorts, 0, sizeof(short int) *
buffersize * NUM_MIDI_PARTS);
+ }
+ 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; 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 -rupN original/src/MusicIO/MusicIO.h new/src/MusicIO/MusicIO.h
--- original/src/MusicIO/MusicIO.h 2012-07-02 21:20:36.000000000 +0000
+++ new/src/MusicIO/MusicIO.h 2013-04-03 20:59:51.000000000 +0000
@@ -42,8 +42,8 @@ class MusicIO : virtual protected MiscFu
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];
+ float *zynRight [NUM_MIDI_PARTS];
short int *interleavedShorts;
int rtprio;
};
diff -rupN original/src/version.txt new/src/version.txt
--- original/src/version.txt 2012-07-02 21:20:37.000000000 +0000
+++ new/src/version.txt 2013-04-03 19:13:57.000000000 +0000
@@ -1 +1 @@
-1.0.0
+1.0.0
\ No newline at end of file

Other related posts:

  • » [yoshimi-user] Patch for Separate Jack Audio Outputs for every channel (patch file included) - Дерябин Андрей