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

  • From: Дерябин Андрей <andrewderyabin@xxxxxxxxx>
  • To: yoshimi-user@xxxxxxxxxxxxxxxxxxxxx
  • Date: Sun, 07 Apr 2013 11:00:14 +0000

Hello, All!

(dont know if my previous message delivered, so sending it again)

I found and fixed output sound clipping for mixed output channels. (I dont know how it worked in general :) ).
The error was that mixed output buffer not cleared in every iteration and next output summed to previous.

Patch included to this e-mail.

P.S. Nikita, thanks for testing :).


06.04.2013 07:15, Nikita Zlobin пишет:

В Sat, 6 Apr 2013 13:11:45 +0600
Nikita Zlobin <cook60020tmp@xxxxxxx> пишет:

I tried yoshimi with latest patch, which provides both master and
per-channel outputs. I can describe this effect only as some
kind of resonance. It doesn't appear on per-channel output.

To change ADsynth default sine wave to Diode with maximum function
parameter (to make it sharper). Effect will appear when master volume
is set enough high (100 should be enough), but on lowed values it
doesn't appear.
Btw, in zynaddsubfx 2.4.3 release this bug doesn't appear.
------------------------------------------------------------------------------
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

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


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/2] 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


From 457decb65c8b7069c88931680c6bc9d0f8b1cfbd Mon Sep 17 00:00:00 2001
From: Andrew Deryabin <andrewderyabin@xxxxxxxxx>
Date: Sat, 6 Apr 2013 23:43:03 +0400
Subject: [PATCH 2/2] Add-support-for-multiple-jack-outputs

---
src/Misc/SynthEngine.cpp | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/src/Misc/SynthEngine.cpp b/src/Misc/SynthEngine.cpp
index 5f063c4..4d8f775 100644
--- a/src/Misc/SynthEngine.cpp
+++ b/src/Misc/SynthEngine.cpp
@@ -360,7 +360,7 @@ void SynthEngine::partonoff(int npart, int what)
void SynthEngine::MasterAudio(float *outl [NUM_MIDI_PARTS], float *outr
[NUM_MIDI_PARTS])
{
int npart;
- for (npart = 0; npart < NUM_MIDI_PARTS; ++npart)
+ for (npart = 0; npart < (NUM_MIDI_PARTS + 1); ++npart)
{
memset(outl[npart], 0, bufferbytes);
memset(outr[npart], 0, bufferbytes);
--
1.8.2


Other related posts: