Skip to content

Commit

Permalink
EMA version 3.1.0
Browse files Browse the repository at this point in the history
More fixes and updates
Included platt source code
  • Loading branch information
suaefar committed Dec 17, 2020
1 parent 14c9b05 commit 8339a9c
Show file tree
Hide file tree
Showing 133 changed files with 6,611 additions and 203 deletions.
4 changes: 2 additions & 2 deletions COPYING
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
Measurement and simulation framework
Copyright (C) 2020 Marc René Schädler
E-mail: marc.r[email protected]
Author (2020) Marc René Schädler
E-mail: marc.rene[email protected]

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
Expand Down
16 changes: 7 additions & 9 deletions LICENSE
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
GNU GENERAL PUBLIC LICENSE
Version 3, 29 June 2007

Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
Copyright (C) 2007 Free Software Foundation, Inc. <https://fsf.org/>
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.

Expand Down Expand Up @@ -631,8 +631,8 @@ to attach them to the start of each source file to most effectively
state the exclusion of warranty; and each file should have at least
the "copyright" line and a pointer to where the full notice is found.

{one line to give the program's name and a brief idea of what it does.}
Copyright (C) {year} {name of author}
<one line to give the program's name and a brief idea of what it does.>
Copyright (C) <year> <name of author>

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
Expand All @@ -645,14 +645,14 @@ the "copyright" line and a pointer to where the full notice is found.
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
along with this program. If not, see <https://www.gnu.org/licenses/>.

Also add information on how to contact you by electronic and paper mail.

If the program does terminal interaction, make it output a short
notice like this when it starts in an interactive mode:

{project} Copyright (C) {year} {fullname}
<program> Copyright (C) <year> <name of author>
This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
This is free software, and you are welcome to redistribute it
under certain conditions; type `show c' for details.
Expand All @@ -664,13 +664,11 @@ might be different; for a GUI interface, you would use an "about box".
You should also get your employer (if you work as a programmer) or school,
if any, to sign a "copyright disclaimer" for the program, if necessary.
For more information on this, and how to apply and follow the GNU GPL, see
<http://www.gnu.org/licenses/>.
<https://www.gnu.org/licenses/>.

The GNU General Public License does not permit incorporating your program
into proprietary programs. If your program is a subroutine library, you
may consider it more useful to permit linking proprietary applications with
the library. If this is what you want to do, use the GNU Lesser General
Public License instead of this License. But first, please read
<http://www.gnu.org/philosophy/why-not-lgpl.html>.


<https://www.gnu.org/licenses/why-not-lgpl.html>.
12 changes: 7 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,9 @@ This expert software framework can be used to implement, perform, and simulate (
Measurements and simulations are tightly integrated, such that all implemented measurements can be performed and simulated with the same code base.
The implementations are modular, such that they can be exchanged or used in other contexts.

Copyright (C) 2020 Marc René Schädler
Author (2020) Marc René Schädler

E-mail: marc.r[email protected]
E-mail: marc.rene[email protected]

The repository currently contains a largely undocumented (but fully functional) code drop.
The documentation will be added on demand over time.
Expand Down Expand Up @@ -48,7 +48,7 @@ However, your audio setup needs to be calibrated before using it.
The calibration and compensation tools reside in `loop`.
Please have a look at the `loop/tools/update_configuration.m`.
The parameters for the calibration of your setup can be set there.
Comment out the line which deliberately generates an error.
Comment out the line which deliberately throws an error.

The provided configuration works well for the Focusrite Scarlett 2i2 sound card and Sennheiser HDA 200 headphones.
`ema/ema.sh` provides a menu for checking the calibration with narrow band noise signals.
Expand Down Expand Up @@ -90,8 +90,10 @@ Please have a look at the preconfigured example in `data/processing/openMHA9_una
All measurements can be combined with all hearing device models, which allows to measure the aided performance in psychoacoustic and speech recognition tasks.

It is also easy to extend the framework with own JACK plugins for aided measurements.
For example the [PLATT dynamic compressor](https://github.com/m-r-s/platt) will also be available once the corresponding code is available.

For example the [PLATT dynamic compressor](https://github.com/m-r-s/platt) is also available.
PLATT is an implementation of a [patented dynamic compression scheme](https://www.innowi.de/de/unsere_patente/details/dynamikkompression-uol169) that aims to preserve speech intelligibility.
Its engineered towards the use in hearing devices (it's fast).
Still, it produces high quality signals (it minimizes compression).

# References
[1] Schädler, M. R., Warzybok, A., Ewert, S. D., Kollmeier, B. (2016) "A simulation framework for auditory discrimination experiments: Revealing the importance of across-frequency processing in speech perception", Journal of the Acoustical Society of America, Volume 139, Issue 5, pp. 2708–2723, URL: http://link.aip.org/link/?JAS/139/2708
Expand Down
1 change: 1 addition & 0 deletions abhang/src/configuration/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
This directory holds the binary configuration files
7 changes: 7 additions & 0 deletions abhang/src/core/constants.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
#ifndef __CONSTANTS_H__
#define __CONSTANTS_H__

#define SAMPLERATE 48000 // samplerate in Hz
#define TICKSAMPLES 48 // ~approx 1ms
#define FEEDBACKLENGTH 20 // N * TICKSAMPLES
#endif
56 changes: 56 additions & 0 deletions abhang/src/core/feedback.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
void
feedback(float const * const in1,
float const * const in2,
float * const out,
float * const playbackbuffer,
float const * const feedbackresponse,
int const * const range
)
{
int feedbacksamples = FEEDBACKLENGTH*TICKSAMPLES;
// Calculate feedback from playback
{
for (int i=0;i<TICKSAMPLES;i++) {
float feedback_tmp = 0.0;

// Determine integration ranges
{
// Range in feedback
int start1 = range[0];
int stop1 = range[1];
// Cursor in playbackbuffer
int o1 = tickcount*TICKSAMPLES;
// Range in playbackbuffer
int start2 = (feedbacksamples+o1+i-start1)%feedbacksamples;
int stop2 = (feedbacksamples+o1+i-stop1)%feedbacksamples;
int o2 = start1;
if (stop2 <= start2) {
for (int j=start2;j>=stop2;j--) {
feedback_tmp += playbackbuffer[j] * feedbackresponse[o2];
o2++;
}
} else {
for (int j=start2;j>=0;j--) {
feedback_tmp += playbackbuffer[j] * feedbackresponse[o2];
o2++;
}
for (int j=feedbacksamples-1;j>=stop2;j--) {
feedback_tmp += playbackbuffer[j] * feedbackresponse[o2];
o2++;
}
}
}
// Remove estimated feedback signal from recording
out[i] = in1[i] - feedback_tmp;
}
}

// Copy new samples to the playbackbuffer
{
int o1 = tickcount*TICKSAMPLES;
for (int i=0;i<TICKSAMPLES;i++) {
playbackbuffer[o1] = in2[i];
o1++;
}
}
}
7 changes: 7 additions & 0 deletions abhang/src/core/variables.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
float feedback1[FEEDBACKLENGTH*TICKSAMPLES] = {0.0};
float feedback2[FEEDBACKLENGTH*TICKSAMPLES] = {0.0};
float playbackbuffer1[FEEDBACKLENGTH*TICKSAMPLES] = {0.0};
float playbackbuffer2[FEEDBACKLENGTH*TICKSAMPLES] = {0.0};
int range1[2] = {0};
int range2[2] = {0};
int tickcount = 0;
205 changes: 205 additions & 0 deletions abhang/src/jack/abhang.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,205 @@
#include <stdio.h>
#include <errno.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <jack/jack.h>
#include <math.h>
#include "constants.h"
#include "variables.h"
#include "feedback.c"

#define DEBUG 1

jack_port_t *input_port1, *input_port2, *input_port3, *input_port4;
jack_port_t *output_port1, *output_port2;
jack_client_t *client;

int
process (jack_nframes_t nframes, void *arg)
{
jack_default_audio_sample_t *in1, *in2, *in3, *in4, *out1, *out2;

in1 = jack_port_get_buffer (input_port1, nframes);
in2 = jack_port_get_buffer (input_port2, nframes);
in3 = jack_port_get_buffer (input_port3, nframes);
in4 = jack_port_get_buffer (input_port4, nframes);
out1 = jack_port_get_buffer (output_port1, nframes);
out2 = jack_port_get_buffer (output_port2, nframes);

if (nframes%TICKSAMPLES != 0) {
printf("ERROR! nframes (%i) no multiple of %i\n",nframes,TICKSAMPLES);
return 1;
} else {
for (int i=0; i<nframes; i+=TICKSAMPLES) {
// PROCESS!
feedback(&in1[i], &in3[i], &out1[i], playbackbuffer1, feedback1, range1);
feedback(&in2[i], &in4[i], &out2[i], playbackbuffer2, feedback2, range2);
tickcount = (tickcount+1)%FEEDBACKLENGTH;
}
}
return 0;
}

/**
* JACK calls this shutdown_callback if the server ever shuts down or
* decides to disconnect the client.
*/
void
jack_shutdown (void *arg)
{
exit (1);
}

int
main (int argc, char *argv[])
{
const char *client_name = "abhang";
const char *server_name = NULL;
jack_options_t options = JackNullOption;
jack_status_t status;
FILE *fp;

printf("Static Feedback Cancelation\n");
// Load FEEDBACK
fp = fopen("configuration/feedback1.bin","rb");
if(fp == NULL) {
printf("Error opening 'configuration/feedback1.bin'\n");
exit (1);
}
fread(feedback1,sizeof(feedback1),1,fp);
fclose(fp);
fp = fopen("configuration/feedback2.bin","rb");
if(fp == NULL) {
printf("Error opening 'configuration/feedback2.bin'\n");
exit (1);
}
fread(feedback2,sizeof(feedback2),1,fp);
fclose(fp);

// Load FEEDBACK RANGE
fp = fopen("configuration/range1.bin","rb");
if(fp == NULL) {
printf("Error opening 'configuration/range1.bin'\n");
exit (1);
}
fread(range1,sizeof(range1),1,fp);
fclose(fp);
fp = fopen("configuration/range2.bin","rb");
if(fp == NULL) {
printf("Error opening 'configuration/range2.bin'\n");
exit (1);
}
fread(range2,sizeof(range2),1,fp);
fclose(fp);

#ifdef DEBUG
printf("\n");
printf("SAMPLERATE: %i\n",SAMPLERATE);
printf("TICKSAMPLES: %i\n",TICKSAMPLES);
printf("FEEDBACKLENGTH: %i\n",FEEDBACKLENGTH);
printf("\n");

for (int i=0;i<TICKSAMPLES*FEEDBACKLENGTH;i++) {
printf("feedback1[%i] = [%.8f]\n",i,feedback1[i]);
}
printf("\n");
for (int i=0;i<TICKSAMPLES*FEEDBACKLENGTH;i++) {
printf("feedback2[%i] = [%.8f]\n",i,feedback2[i]);
}
printf("range1[0,1] = [%i %i]\n",range1[0],range1[1]);
printf("range2[0,1] = [%i %i]\n",range2[0],range2[1]);
printf("\n");

#endif

/* open a client connection to the JACK server */
client = jack_client_open (client_name, options, &status, server_name);
if (client == NULL) {
fprintf (stderr, "jack_client_open() failed, "
"status = 0x%2.0x\n", status);
if (status & JackServerFailed) {
fprintf (stderr, "Unable to connect to JACK server\n");
}
exit (1);
}
if (status & JackServerStarted) {
fprintf (stderr, "JACK server started\n");
}
if (status & JackNameNotUnique) {
client_name = jack_get_client_name(client);
fprintf (stderr, "unique name `%s' assigned\n", client_name);
}

// Check if we are in spec
if (jack_get_sample_rate (client) != SAMPLERATE) {
fprintf (stderr, "sample rate (%i!=%i) not supported!\n", jack_get_sample_rate (client), SAMPLERATE);
exit (1);
}

/* tell the JACK server to call `process()' whenever
there is work to be done.
*/

jack_set_process_callback (client, process, 0);

/* tell the JACK server to call `jack_shutdown()' if
it ever shuts down, either entirely, or if it
just decides to stop calling us.
*/

jack_on_shutdown (client, jack_shutdown, 0);

/* display the current sample rate.
*/

printf ("engine sample rate: %" PRIu32 "\n",
jack_get_sample_rate (client));

/* create two ports */

input_port1 = jack_port_register (client, "input_1",
JACK_DEFAULT_AUDIO_TYPE,
JackPortIsInput, 0);
input_port2 = jack_port_register (client, "input_2",
JACK_DEFAULT_AUDIO_TYPE,
JackPortIsInput, 0);
input_port3 = jack_port_register (client, "input_3",
JACK_DEFAULT_AUDIO_TYPE,
JackPortIsInput, 0);
input_port4 = jack_port_register (client, "input_4",
JACK_DEFAULT_AUDIO_TYPE,
JackPortIsInput, 0);

output_port1 = jack_port_register (client, "output_1",
JACK_DEFAULT_AUDIO_TYPE,
JackPortIsOutput, 0);
output_port2 = jack_port_register (client, "output_2",
JACK_DEFAULT_AUDIO_TYPE,
JackPortIsOutput, 0);

if ((input_port1 == NULL) || (input_port2 == NULL) || (input_port3 == NULL) || (input_port4 == NULL) || (output_port1 == NULL) || (output_port2 == NULL) ) {
fprintf(stderr, "no more JACK ports available\n");
exit (1);
}

/* Tell the JACK server that we are ready to roll. Our
* process() callback will start running now. */

if (jack_activate (client)) {
fprintf (stderr, "cannot activate client");
exit (1);
}

/* keep running until stopped by the user */

sleep (-1);

/* this is never reached but if the program
had some other way to exit besides being killed,
they would be important to call.
*/

jack_client_close (client);
exit (0);
}
1 change: 1 addition & 0 deletions abhang/src/jack/configuration
1 change: 1 addition & 0 deletions abhang/src/jack/constants.h
1 change: 1 addition & 0 deletions abhang/src/jack/feedback.c
1 change: 1 addition & 0 deletions abhang/src/jack/variables.h
Loading

0 comments on commit 8339a9c

Please sign in to comment.