@@ -0,0 +1,75 @@ | |||
/* | |||
* Carla Native Plugins | |||
* Copyright (C) 2013 Filipe Coelho <falktx@falktx.com> | |||
* | |||
* 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 the Free Software Foundation; either version 2 of | |||
* the License, or any later version. | |||
* | |||
* This program is distributed in the hope that it will be useful, | |||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||
* GNU General Public License for more details. | |||
* | |||
* For a full copy of the GNU General Public License see the GPL.txt file | |||
*/ | |||
#include "CarlaNative.h" | |||
// Plugin Code | |||
#include "nekofilter/nekofilter.c" | |||
#include "nekofilter/filter.c" | |||
#include "nekofilter/log.c" | |||
// ----------------------------------------------------------------------- | |||
static const PluginDescriptor nekofilterDesc = { | |||
.category = PLUGIN_CATEGORY_FILTER, | |||
.hints = PLUGIN_IS_RTSAFE|PLUGIN_HAS_GUI, | |||
.audioIns = 1, | |||
.audioOuts = 1, | |||
.midiIns = 0, | |||
.midiOuts = 0, | |||
.parameterIns = GLOBAL_PARAMETERS_COUNT + BAND_PARAMETERS_COUNT*BANDS_COUNT, | |||
.parameterOuts = 0, | |||
.name = "NekoFilter", | |||
.label = "nekofilter", | |||
.maker = "falkTX, Nedko, Fons Adriaensen", | |||
.copyright = "GNU GPL v2+", | |||
.instantiate = nekofilter_instantiate, | |||
.cleanup = nekofilter_cleanup, | |||
.get_parameter_count = nekofilter_get_parameter_count, | |||
.get_parameter_info = nekofilter_get_parameter_info, | |||
.get_parameter_value = nekofilter_get_parameter_value, | |||
.get_parameter_text = NULL, | |||
.get_midi_program_count = NULL, | |||
.get_midi_program_info = NULL, | |||
.set_parameter_value = nekofilter_set_parameter_value, | |||
.set_midi_program = NULL, | |||
.set_custom_data = NULL, | |||
.ui_show = nekofilter_ui_show, | |||
.ui_idle = nekofilter_ui_idle, | |||
.ui_set_parameter_value = nekofilter_ui_set_parameter_value, | |||
.ui_set_midi_program = NULL, | |||
.ui_set_custom_data = NULL, | |||
.activate = NULL, | |||
.deactivate = NULL, | |||
.process = nekofilter_process | |||
}; | |||
// ----------------------------------------------------------------------- | |||
void carla_register_native_plugin_nekofilter() | |||
{ | |||
carla_register_native_plugin(&nekofilterDesc); | |||
} | |||
// ----------------------------------------------------------------------- |
@@ -0,0 +1,350 @@ | |||
/* -*- Mode: C ; c-basic-offset: 2 -*- */ | |||
/* | |||
Copyright (C) 2008 Nedko Arnaudov <nedko@arnaudov.name> | |||
The DSP code is based on ladspa:1970 by Fons Adriaensen | |||
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 | |||
the Free Software Foundation; either version 2 of the License, or | |||
(at your option) any later version. | |||
This program is distributed in the hope that it will be useful, | |||
but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||
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, write to the Free Software | |||
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | |||
*/ | |||
/* if NDEBUG is defined, assert checks are disabled */ | |||
//#define NDEBUG | |||
#include <stdbool.h> | |||
#include <stdlib.h> | |||
#include <string.h> | |||
#include <math.h> | |||
#include <assert.h> | |||
#include "filter.h" | |||
static float exp2ap(float x) | |||
{ | |||
int i; | |||
i = (int)(floor(x)); | |||
x -= i; | |||
// return ldexp(1 + x * (0.66 + 0.34 * x), i); | |||
return ldexp(1 + x * (0.6930 + x * (0.2416 + x * (0.0517 + x * 0.0137))), i); | |||
} | |||
struct param_sect | |||
{ | |||
float f, b, g; | |||
float s1, s2, a; | |||
float z1, z2; | |||
}; | |||
void | |||
param_sect_init( | |||
struct param_sect * sect_ptr) | |||
{ | |||
sect_ptr->f = 0.25f; | |||
sect_ptr->b = sect_ptr->g = 1.0f; | |||
sect_ptr->a = sect_ptr->s1 = sect_ptr->s2 = sect_ptr->z1 = sect_ptr->z2 = 0.0f; | |||
} | |||
void | |||
param_sect_proc( | |||
struct param_sect * sect_ptr, | |||
int k, | |||
float * sig, | |||
float f, | |||
float b, | |||
float g) | |||
{ | |||
float s1, s2, d1, d2, a, da, x, y; | |||
bool u2 = false; | |||
s1 = sect_ptr->s1; | |||
s2 = sect_ptr->s2; | |||
a = sect_ptr->a; | |||
d1 = 0; | |||
d2 = 0; | |||
da = 0; | |||
if (f != sect_ptr->f) | |||
{ | |||
if (f < 0.5f * sect_ptr->f) f = 0.5f * sect_ptr->f; | |||
else if (f > 2.0f * sect_ptr->f) f = 2.0f * sect_ptr->f; | |||
sect_ptr->f = f; | |||
sect_ptr->s1 = -cosf(6.283185f * f); | |||
d1 = (sect_ptr->s1 - s1) / k; | |||
u2 = true; | |||
} | |||
if (g != sect_ptr->g) | |||
{ | |||
if (g < 0.5f * sect_ptr->g) g = 0.5f * sect_ptr->g; | |||
else if (g > 2.0f * sect_ptr->g) g = 2.0f * sect_ptr->g; | |||
sect_ptr->g = g; | |||
sect_ptr->a = 0.5f * (g - 1.0f); | |||
da = (sect_ptr->a - a) / k; | |||
u2 = true; | |||
} | |||
if (b != sect_ptr->b) | |||
{ | |||
if (b < 0.5f * sect_ptr->b) b = 0.5f * sect_ptr->b; | |||
else if (b > 2.0f * sect_ptr->b) b = 2.0f * sect_ptr->b; | |||
sect_ptr->b = b; | |||
u2 = true; | |||
} | |||
if (u2) | |||
{ | |||
b *= 7 * f / sqrtf(g); | |||
sect_ptr->s2 = (1 - b) / (1 + b); | |||
d2 = (sect_ptr->s2 - s2) / k; | |||
} | |||
while (k--) | |||
{ | |||
s1 += d1; | |||
s2 += d2; | |||
a += da; | |||
x = *sig; | |||
y = x - s2 * sect_ptr->z2; | |||
*sig++ -= a * (sect_ptr->z2 + s2 * y - x); | |||
y -= s1 * sect_ptr->z1; | |||
sect_ptr->z2 = sect_ptr->z1 + s1 * y; | |||
sect_ptr->z1 = y + 1e-10f; | |||
} | |||
} | |||
struct filter | |||
{ | |||
float sample_rate; | |||
const float * global_parameters[GLOBAL_PARAMETERS_COUNT]; | |||
unsigned int bands_count; | |||
const float ** band_parameters; /* [band_index * BAND_PARAMETERS_COUNT + parameter_index] */ | |||
float gain; | |||
int fade; | |||
struct param_sect * sect; /* [band_index] */ | |||
}; | |||
bool | |||
filter_create( | |||
float sample_rate, | |||
unsigned int bands_count, | |||
filter_handle * handle_ptr) | |||
{ | |||
struct filter * filter_ptr; | |||
unsigned int j; | |||
assert(bands_count > 0); | |||
filter_ptr = calloc(1, sizeof(struct filter)); | |||
if (filter_ptr == NULL) | |||
{ | |||
goto fail; | |||
} | |||
filter_ptr->band_parameters = calloc(bands_count, sizeof(float *) * BAND_PARAMETERS_COUNT); | |||
if (filter_ptr->band_parameters == NULL) | |||
{ | |||
goto free_filter; | |||
} | |||
filter_ptr->sect = malloc(sizeof(struct param_sect) * bands_count); | |||
if (filter_ptr->sect == NULL) | |||
{ | |||
goto free_band_params; | |||
} | |||
filter_ptr->sample_rate = sample_rate; | |||
filter_ptr->bands_count = bands_count; | |||
filter_ptr->fade = 0; | |||
filter_ptr->gain = 1.0; | |||
for (j = 0; j < bands_count; j++) | |||
{ | |||
param_sect_init(filter_ptr->sect + j); | |||
} | |||
*handle_ptr = (filter_handle)filter_ptr; | |||
return true; | |||
free_band_params: | |||
free(filter_ptr->band_parameters); | |||
free_filter: | |||
free(filter_ptr); | |||
fail: | |||
return false; | |||
} | |||
#define filter_ptr ((struct filter *)handle) | |||
void | |||
filter_destroy( | |||
filter_handle handle) | |||
{ | |||
free(filter_ptr->sect); | |||
free(filter_ptr->band_parameters); | |||
free(filter_ptr); | |||
} | |||
void | |||
filter_connect_global_parameter( | |||
filter_handle handle, | |||
unsigned int global_parameter, | |||
const float * value_ptr) | |||
{ | |||
assert(global_parameter < GLOBAL_PARAMETERS_COUNT); | |||
filter_ptr->global_parameters[global_parameter] = value_ptr; | |||
} | |||
void | |||
filter_connect_band_parameter( | |||
filter_handle handle, | |||
unsigned int band_index, | |||
unsigned int band_parameter, | |||
const float * value_ptr) | |||
{ | |||
assert(band_index < filter_ptr->bands_count); | |||
assert(band_parameter < BAND_PARAMETERS_COUNT); | |||
filter_ptr->band_parameters[band_index * BAND_PARAMETERS_COUNT + band_parameter] = value_ptr; | |||
} | |||
void | |||
filter_run( | |||
filter_handle handle, | |||
const float * input_buffer, | |||
float * output_buffer, | |||
unsigned long samples_count) | |||
{ | |||
int i, j, k; | |||
const float * p; | |||
float sig[48]; | |||
float t, g, d; | |||
float fgain; | |||
float sfreq[filter_ptr->bands_count]; | |||
float sband[filter_ptr->bands_count]; | |||
float sgain[filter_ptr->bands_count]; | |||
float bands_count; | |||
bands_count = filter_ptr->bands_count; | |||
fgain = exp2ap(0.1661 * *filter_ptr->global_parameters[GLOBAL_PARAMETER_GAIN]); | |||
for (j = 0; j < bands_count; j++) | |||
{ | |||
t = *filter_ptr->band_parameters[BAND_PARAMETERS_COUNT * j + BAND_PARAMETER_FREQUENCY] / filter_ptr->sample_rate; | |||
if (t < 0.0002) | |||
{ | |||
t = 0.0002; | |||
} | |||
else if (t > 0.4998) | |||
{ | |||
t = 0.4998; | |||
} | |||
sfreq[j] = t; | |||
sband[j] = *filter_ptr->band_parameters[BAND_PARAMETERS_COUNT * j + BAND_PARAMETER_BANDWIDTH]; | |||
if (*filter_ptr->band_parameters[BAND_PARAMETERS_COUNT * j + BAND_PARAMETER_ACTIVE] > 0.0) | |||
{ | |||
sgain[j] = exp2ap(0.1661 * *filter_ptr->band_parameters[BAND_PARAMETERS_COUNT * j + BAND_PARAMETER_GAIN]); | |||
} | |||
else | |||
{ | |||
sgain[j] = 1.0; | |||
} | |||
} | |||
while (samples_count) | |||
{ | |||
k = (samples_count > 48) ? 32 : samples_count; | |||
t = fgain; | |||
g = filter_ptr->gain; | |||
if (t > 1.25 * g) | |||
{ | |||
t = 1.25 * g; | |||
} | |||
else if (t < 0.80 * g) | |||
{ | |||
t = 0.80 * g; | |||
} | |||
filter_ptr->gain = t; | |||
d = (t - g) / k; | |||
for (i = 0; i < k; i++) | |||
{ | |||
g += d; | |||
sig[i] = g * input_buffer[i]; | |||
} | |||
for (j = 0; j < bands_count; j++) | |||
{ | |||
param_sect_proc(filter_ptr->sect + j, k, sig, sfreq[j], sband[j], sgain[j]); | |||
} | |||
j = filter_ptr->fade; | |||
g = j / 16.0; | |||
p = 0; | |||
if (*filter_ptr->global_parameters[GLOBAL_PARAMETER_ACTIVE] > 0.0) | |||
{ | |||
if (j == 16) | |||
{ | |||
p = sig; | |||
} | |||
else | |||
{ | |||
++j; | |||
} | |||
} | |||
else | |||
{ | |||
if (j == 0) | |||
{ | |||
p = input_buffer; | |||
} | |||
else | |||
{ | |||
--j; | |||
} | |||
} | |||
filter_ptr->fade = j; | |||
if (p) | |||
{ | |||
memcpy(output_buffer, p, k * sizeof(float)); | |||
} | |||
else | |||
{ | |||
d = (j / 16.0 - g) / k; | |||
for (i = 0; i < k; i++) | |||
{ | |||
g += d; | |||
output_buffer[i] = g * sig[i] + (1 - g) * input_buffer[i]; | |||
} | |||
} | |||
input_buffer += k; | |||
output_buffer += k; | |||
samples_count -= k; | |||
} | |||
} |
@@ -0,0 +1,65 @@ | |||
/* -*- Mode: C ; c-basic-offset: 2 -*- */ | |||
/* | |||
Copyright (C) 2008 Nedko Arnaudov <nedko@arnaudov.name> | |||
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 | |||
the Free Software Foundation; either version 2 of the License, or | |||
(at your option) any later version. | |||
This program is distributed in the hope that it will be useful, | |||
but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||
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, write to the Free Software | |||
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | |||
*/ | |||
#ifndef FILTER_H__D5DC5ADF_211A_48F6_93A5_68CD3B73D6C5__INCLUDED | |||
#define FILTER_H__D5DC5ADF_211A_48F6_93A5_68CD3B73D6C5__INCLUDED | |||
typedef struct {int unused; } * filter_handle; | |||
#define GLOBAL_PARAMETER_ACTIVE 0 | |||
#define GLOBAL_PARAMETER_GAIN 1 | |||
#define GLOBAL_PARAMETERS_COUNT 2 | |||
#define BAND_PARAMETER_ACTIVE 0 | |||
#define BAND_PARAMETER_FREQUENCY 1 | |||
#define BAND_PARAMETER_BANDWIDTH 2 | |||
#define BAND_PARAMETER_GAIN 3 | |||
#define BAND_PARAMETERS_COUNT 4 | |||
bool | |||
filter_create( | |||
float sample_rate, | |||
unsigned int bands_count, | |||
filter_handle * handle_ptr); | |||
void | |||
filter_connect_global_parameter( | |||
filter_handle handle, | |||
unsigned int global_parameter, | |||
const float * value_ptr); | |||
void | |||
filter_connect_band_parameter( | |||
filter_handle handle, | |||
unsigned int band_index, | |||
unsigned int band_parameter, | |||
const float * value_ptr); | |||
void | |||
filter_run( | |||
filter_handle handle, | |||
const float * input_buffer, | |||
float * output_buffer, | |||
unsigned long samples_count); | |||
void | |||
filter_destroy( | |||
filter_handle handle); | |||
#endif /* #ifndef FILTER_H__D5DC5ADF_211A_48F6_93A5_68CD3B73D6C5__INCLUDED */ |
@@ -0,0 +1,40 @@ | |||
/* -*- Mode: C ; c-basic-offset: 2 -*- */ | |||
/***************************************************************************** | |||
* | |||
* Copyright (C) 2006,2007,2008,2009 Nedko Arnaudov <nedko@arnaudov.name> | |||
* | |||
* 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 | |||
* the Free Software Foundation; version 2 of the License | |||
* | |||
* This program is distributed in the hope that it will be useful, | |||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||
* 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, write to the Free Software | |||
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. | |||
* | |||
*****************************************************************************/ | |||
#include <stdio.h> | |||
#include <stdlib.h> | |||
#include <stdarg.h> | |||
#include <string.h> | |||
#include "log.h" | |||
void nekolog(int level, const char * format, ...) | |||
{ | |||
va_list arglist; | |||
va_start(arglist, format); | |||
vprintf(format, arglist); | |||
va_end(arglist); | |||
return; | |||
//unused | |||
(void)level; | |||
} |
@@ -0,0 +1,86 @@ | |||
/* -*- Mode: C ; c-basic-offset: 2 -*- */ | |||
/***************************************************************************** | |||
* | |||
* Copyright (C) 2006,2007,2008,2009 Nedko Arnaudov <nedko@arnaudov.name> | |||
* | |||
* 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 | |||
* the Free Software Foundation; version 2 of the License | |||
* | |||
* This program is distributed in the hope that it will be useful, | |||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||
* 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, write to the Free Software | |||
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. | |||
* | |||
*****************************************************************************/ | |||
#ifndef LOG_H__7097F6FE_4FEE_4962_9542_60375961F567__INCLUDED | |||
#define LOG_H__7097F6FE_4FEE_4962_9542_60375961F567__INCLUDED | |||
void nekolog(int level, const char * format, ...); | |||
#define LOG_LEVEL_DEBUG 0 | |||
#define LOG_LEVEL_INFO 1 | |||
#define LOG_LEVEL_WARNING 2 | |||
#define LOG_LEVEL_NOTICE 3 | |||
#define LOG_LEVEL_ERROR 4 | |||
#define LOG_LEVEL_FATAL 5 | |||
#define LOG_LEVEL_BLACK_HOLE 6 | |||
#if !defined(LOG_LEVEL) | |||
#define LOG_LEVEL LOG_LEVEL_WARNING | |||
#endif | |||
#if LOG_LEVEL <= LOG_LEVEL_DEBUG | |||
# define LOG_DEBUG(format, arg...) \ | |||
nekolog(LOG_LEVEL_DEBUG, \ | |||
format "\n", ## arg) | |||
#else | |||
# define LOG_DEBUG(format, arg...) | |||
#endif | |||
#if LOG_LEVEL <= LOG_LEVEL_INFO | |||
# define LOG_INFO(format, arg...) \ | |||
nekolog(LOG_LEVEL_INFO, \ | |||
format "\n", ## arg) | |||
#else | |||
# define LOG_INFO(format, arg...) | |||
#endif | |||
#if LOG_LEVEL <= LOG_LEVEL_WARNING | |||
# define LOG_WARNING(format, arg...) \ | |||
nekolog(LOG_LEVEL_WARNING, \ | |||
format "\n", ## arg) | |||
#else | |||
# define LOG_WARNING(format, arg...) | |||
#endif | |||
#if LOG_LEVEL <= LOG_LEVEL_NOTICE | |||
# define LOG_NOTICE(format, arg...) \ | |||
nekolog(LOG_LEVEL_NOTICE, \ | |||
format "\n", ## arg) | |||
#else | |||
# define LOG_NOTICE(format, arg...) | |||
#endif | |||
#if LOG_LEVEL <= LOG_LEVEL_ERROR | |||
# define LOG_ERROR(format, arg...) \ | |||
nekolog(LOG_LEVEL_ERROR, \ | |||
format "\n", ## arg) | |||
#else | |||
# define LOG_ERROR(format, arg...) | |||
#endif | |||
#if LOG_LEVEL <= LOG_LEVEL_FATAL | |||
# define LOG_FATAL(format, arg...) \ | |||
nekolog(LOG_LEVEL_FATAL, \ | |||
format "\n", ## arg) | |||
#else | |||
# define LOG_FATAL(format, arg...) | |||
#endif | |||
#endif /* #ifndef LOG_H__7097F6FE_4FEE_4962_9542_60375961F567__INCLUDED */ |
@@ -0,0 +1,396 @@ | |||
/* -*- Mode: C ; c-basic-offset: 2 -*- */ | |||
/***************************************************************************** | |||
* | |||
* Copyright (C) 2006,2007,2008,2009 Nedko Arnaudov <nedko@arnaudov.name> | |||
* Copyright (C) 2013 Filipe Coelho <falktx@falktx.com> | |||
* | |||
* 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 | |||
* the Free Software Foundation; version 2 of the License | |||
* | |||
* This program is distributed in the hope that it will be useful, | |||
* but WITHOUT ANY WARRANTY; without even the implied warranty of | |||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |||
* 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, write to the Free Software | |||
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. | |||
* | |||
*****************************************************************************/ | |||
#include <stdlib.h> | |||
#include <string.h> | |||
#include <stdio.h> | |||
#include <assert.h> | |||
#include <math.h> | |||
#include <stdbool.h> | |||
#include "CarlaNative.h" | |||
//#include "nekofilter.h" | |||
#include "filter.h" | |||
#define LOG_LEVEL LOG_LEVEL_ERROR | |||
#include "log.h" | |||
#include "ui.c" | |||
#define BANDS_COUNT 4 | |||
struct nekofilter | |||
{ | |||
filter_handle filter; | |||
float params_global[GLOBAL_PARAMETERS_COUNT]; | |||
float params_bands[BAND_PARAMETERS_COUNT*BANDS_COUNT]; | |||
HostDescriptor* host; | |||
struct control* ui; | |||
}; | |||
PluginHandle | |||
nekofilter_instantiate( | |||
const struct _PluginDescriptor* _this_, | |||
HostDescriptor* host) | |||
{ | |||
struct nekofilter * nekofilter_ptr; | |||
unsigned int i; | |||
LOG_DEBUG("nekofilter_create_plugin_instance() called."); | |||
nekofilter_ptr = malloc(sizeof(struct nekofilter)); | |||
if (nekofilter_ptr == NULL) | |||
{ | |||
goto fail; | |||
} | |||
nekofilter_ptr->host = host; | |||
nekofilter_ptr->ui = NULL; | |||
if (!filter_create(host->get_sample_rate(host->handle), BANDS_COUNT, &nekofilter_ptr->filter)) | |||
{ | |||
goto fail_destroy_filter; | |||
} | |||
nekofilter_ptr->params_global[GLOBAL_PARAMETER_ACTIVE] = 0.0f; | |||
nekofilter_ptr->params_global[GLOBAL_PARAMETER_GAIN] = 0.0f; | |||
filter_connect_global_parameter(nekofilter_ptr->filter, | |||
GLOBAL_PARAMETER_ACTIVE, | |||
&nekofilter_ptr->params_global[GLOBAL_PARAMETER_ACTIVE]); | |||
filter_connect_global_parameter(nekofilter_ptr->filter, | |||
GLOBAL_PARAMETER_GAIN, | |||
&nekofilter_ptr->params_global[GLOBAL_PARAMETER_GAIN]); | |||
for (i=0; i < BANDS_COUNT; i++) | |||
{ | |||
nekofilter_ptr->params_bands[i*BAND_PARAMETERS_COUNT + BAND_PARAMETER_ACTIVE] = 0.0f; | |||
nekofilter_ptr->params_bands[i*BAND_PARAMETERS_COUNT + BAND_PARAMETER_FREQUENCY] = 0.0f; | |||
nekofilter_ptr->params_bands[i*BAND_PARAMETERS_COUNT + BAND_PARAMETER_BANDWIDTH] = 1.0f; | |||
nekofilter_ptr->params_bands[i*BAND_PARAMETERS_COUNT + BAND_PARAMETER_GAIN] = 0.0f; | |||
switch (i) | |||
{ | |||
case 0: | |||
nekofilter_ptr->params_bands[i*BAND_PARAMETERS_COUNT + BAND_PARAMETER_FREQUENCY] = 200.0f; | |||
break; | |||
case 1: | |||
nekofilter_ptr->params_bands[i*BAND_PARAMETERS_COUNT + BAND_PARAMETER_FREQUENCY] = 400.0f; | |||
break; | |||
case 2: | |||
nekofilter_ptr->params_bands[i*BAND_PARAMETERS_COUNT + BAND_PARAMETER_FREQUENCY] = 1000.0f; | |||
break; | |||
case 3: | |||
nekofilter_ptr->params_bands[i*BAND_PARAMETERS_COUNT + BAND_PARAMETER_FREQUENCY] = 2000.0f; | |||
break; | |||
} | |||
filter_connect_band_parameter(nekofilter_ptr->filter, | |||
i, | |||
BAND_PARAMETER_ACTIVE, | |||
&nekofilter_ptr->params_bands[i*BAND_PARAMETERS_COUNT + BAND_PARAMETER_ACTIVE]); | |||
filter_connect_band_parameter(nekofilter_ptr->filter, | |||
i, | |||
BAND_PARAMETER_FREQUENCY, | |||
&nekofilter_ptr->params_bands[i*BAND_PARAMETERS_COUNT + BAND_PARAMETER_FREQUENCY]); | |||
filter_connect_band_parameter(nekofilter_ptr->filter, | |||
i, | |||
BAND_PARAMETER_BANDWIDTH, | |||
&nekofilter_ptr->params_bands[i*BAND_PARAMETERS_COUNT + BAND_PARAMETER_BANDWIDTH]); | |||
filter_connect_band_parameter(nekofilter_ptr->filter, | |||
i, | |||
BAND_PARAMETER_GAIN, | |||
&nekofilter_ptr->params_bands[i*BAND_PARAMETERS_COUNT + BAND_PARAMETER_GAIN]); | |||
} | |||
return (PluginHandle)nekofilter_ptr; | |||
fail_destroy_filter: | |||
filter_destroy(nekofilter_ptr->filter); | |||
free(nekofilter_ptr); | |||
fail: | |||
return NULL; | |||
// unused | |||
(void)_this_; | |||
} | |||
#define nekofilter_ptr ((struct nekofilter *)handle) | |||
uint32_t | |||
nekofilter_get_parameter_count( | |||
PluginHandle handle) | |||
{ | |||
return GLOBAL_PARAMETERS_COUNT + BAND_PARAMETERS_COUNT*BANDS_COUNT; | |||
// unused | |||
(void)handle; | |||
} | |||
const Parameter* | |||
nekofilter_get_parameter_info( | |||
PluginHandle handle, | |||
uint32_t index) | |||
{ | |||
static Parameter param; | |||
static bool first_init = true; | |||
uint32_t band; | |||
char strBuf[32]; | |||
if (first_init) | |||
{ | |||
first_init = false; | |||
param.name = NULL; | |||
param.unit = NULL; | |||
} | |||
else | |||
{ | |||
if (param.name != NULL) | |||
{ | |||
free((void*)param.name); | |||
param.name = NULL; | |||
} | |||
if (param.unit != NULL) | |||
{ | |||
free((void*)param.unit); | |||
param.unit = NULL; | |||
} | |||
} | |||
if (handle == NULL && index == 0xf00baa) | |||
// internal cleanup call | |||
return NULL; | |||
param.hints = PARAMETER_IS_ENABLED|PARAMETER_IS_AUTOMABLE; | |||
param.ranges.def = 0.0f; | |||
param.ranges.min = 0.0f; | |||
param.ranges.max = 0.0f; | |||
param.scalePointCount = 0; | |||
param.scalePoints = NULL; | |||
switch (index) | |||
{ | |||
case GLOBAL_PARAMETER_ACTIVE: | |||
param.hints |= PARAMETER_IS_BOOLEAN; | |||
param.name = strdup("Active"); | |||
param.ranges.max = 1.0f; | |||
goto ready; | |||
break; | |||
case GLOBAL_PARAMETER_GAIN: | |||
param.name = strdup("Gain"); | |||
param.unit = strdup("dB"); | |||
param.ranges.min = -20.0f; | |||
param.ranges.max = 20.0f; | |||
goto ready; | |||
break; | |||
} | |||
index -= GLOBAL_PARAMETERS_COUNT; | |||
band = index / BANDS_COUNT; | |||
index %= BANDS_COUNT; | |||
sprintf(strBuf, "%i:", band); | |||
switch (index) | |||
{ | |||
case BAND_PARAMETER_ACTIVE: | |||
strcat(strBuf, "Active"); | |||
param.hints |= PARAMETER_IS_BOOLEAN; | |||
param.name = strdup(strBuf); | |||
param.ranges.max = 1.0f; | |||
break; | |||
case BAND_PARAMETER_FREQUENCY: | |||
strcat(strBuf, "Frequency"); | |||
param.hints |= PARAMETER_IS_LOGARITHMIC; | |||
param.name = strdup(strBuf); | |||
param.unit = strdup("Hz"); | |||
switch (band) | |||
{ | |||
case 0: | |||
param.ranges.min = 20.0f; | |||
param.ranges.max = 2000.0f; | |||
break; | |||
case 1: | |||
param.ranges.min = 40.0f; | |||
param.ranges.max = 4000.0f; | |||
break; | |||
case 2: | |||
param.ranges.min = 100.0f; | |||
param.ranges.max = 10000.0f; | |||
break; | |||
case 3: | |||
param.ranges.min = 200.0f; | |||
param.ranges.max = 20000.0f; | |||
break; | |||
} | |||
break; | |||
case BAND_PARAMETER_BANDWIDTH: | |||
strcat(strBuf, "Bandwidth"); | |||
param.hints |= PARAMETER_IS_LOGARITHMIC; | |||
param.name = strdup(strBuf); | |||
param.ranges.min = 0.125f; | |||
param.ranges.max = 8.0f; | |||
break; | |||
case BAND_PARAMETER_GAIN: | |||
strcat(strBuf, "Gain"); | |||
param.name = strdup(strBuf); | |||
param.unit = strdup("dB"); | |||
param.ranges.min = -20.0f; | |||
param.ranges.max = 20.0f; | |||
break; | |||
} | |||
ready: | |||
if (param.hints & PARAMETER_IS_BOOLEAN) | |||
{ | |||
param.ranges.step = 1.0f; | |||
param.ranges.stepSmall = 1.0f; | |||
param.ranges.stepLarge = 1.0f; | |||
} | |||
else | |||
{ | |||
float range = param.ranges.max - param.ranges.min; | |||
param.ranges.step = range/100.0f; | |||
param.ranges.stepSmall = range/1000.0f; | |||
param.ranges.stepLarge = range/10.0f; | |||
} | |||
return ¶m; | |||
} | |||
float | |||
nekofilter_get_parameter_value( | |||
PluginHandle handle, | |||
uint32_t index) | |||
{ | |||
if (index < GLOBAL_PARAMETERS_COUNT) | |||
{ | |||
return nekofilter_ptr->params_global[index]; | |||
} | |||
else | |||
{ | |||
assert(index >= GLOBAL_PARAMETERS_COUNT); | |||
index -= GLOBAL_PARAMETERS_COUNT; | |||
return nekofilter_ptr->params_bands[index]; | |||
} | |||
} | |||
void | |||
nekofilter_set_parameter_value( | |||
PluginHandle handle, | |||
uint32_t index, | |||
float value) | |||
{ | |||
if (index < GLOBAL_PARAMETERS_COUNT) | |||
{ | |||
nekofilter_ptr->params_global[index] = value; | |||
} | |||
else | |||
{ | |||
assert(index >= GLOBAL_PARAMETERS_COUNT); | |||
index -= GLOBAL_PARAMETERS_COUNT; | |||
nekofilter_ptr->params_bands[index] = value; | |||
} | |||
} | |||
void | |||
nekofilter_process( | |||
PluginHandle handle, | |||
float** inBuffer, | |||
float** outBuffer, | |||
uint32_t frames, | |||
uint32_t midiEventCount, | |||
const MidiEvent* midiEvents) | |||
{ | |||
LOG_DEBUG("nekofilter_run"); | |||
filter_run( | |||
nekofilter_ptr->filter, | |||
inBuffer[0], | |||
outBuffer[0], | |||
frames); | |||
return; | |||
// unused | |||
(void)midiEventCount; | |||
(void)midiEvents; | |||
} | |||
void nekofilter_ui_show( | |||
PluginHandle handle, | |||
bool show) | |||
{ | |||
if (show) | |||
{ | |||
if (nekofilter_ptr->ui == NULL) | |||
nekofilter_ptr->ui = nekoui_instantiate(nekofilter_ptr->host); | |||
nekoui_show(nekofilter_ptr->ui); | |||
} | |||
else if (nekofilter_ptr->ui != NULL) | |||
nekoui_hide(nekofilter_ptr->ui); | |||
} | |||
void nekofilter_ui_idle( | |||
PluginHandle handle) | |||
{ | |||
if (nekofilter_ptr->ui != NULL) | |||
nekoui_run(nekofilter_ptr->ui); | |||
} | |||
void nekofilter_ui_set_parameter_value( | |||
PluginHandle handle, | |||
uint32_t index, | |||
float value) | |||
{ | |||
if (nekofilter_ptr->ui != NULL) | |||
nekoui_set_parameter_value(nekofilter_ptr->ui, index, value); | |||
} | |||
void | |||
nekofilter_cleanup( | |||
PluginHandle handle) | |||
{ | |||
if (nekofilter_ptr->ui != NULL) | |||
{ | |||
nekoui_quit(nekofilter_ptr->ui); | |||
nekoui_cleanup(nekofilter_ptr->ui); | |||
} | |||
filter_destroy(nekofilter_ptr->filter); | |||
free(nekofilter_ptr); | |||
// cleanup static data | |||
nekofilter_get_parameter_info(NULL, 0xf00baa); | |||
} | |||
#undef nekofilter_ptr |
@@ -0,0 +1,522 @@ | |||
/* -*- Mode: C ; c-basic-offset: 2 -*- */ | |||
/***************************************************************************** | |||
* | |||
* Copyright (C) 2009 Nedko Arnaudov <nedko@arnaudov.name> | |||
* Copyright (C) 2013 Filipe Coelho <falktx@falktx.com> | |||
* | |||
* LV2 UI bundle shared library for communicating with a DSSI UI | |||
* | |||
* 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 the Free Software Foundation; either version 2 of | |||
* the License, or (at your option) any later version. | |||
* | |||
* This program is distributed in the hope that it will be | |||
* useful, but WITHOUT ANY WARRANTY; without even the implied | |||
* warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR | |||
* PURPOSE. See the 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, write to the Free | |||
* Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, | |||
* MA 02111-1307, USA. | |||
* | |||
*****************************************************************************/ | |||
#define UI_EXECUTABLE "ui.py" | |||
#define WAIT_START_TIMEOUT 3000 /* ms */ | |||
#define WAIT_ZOMBIE_TIMEOUT 3000 /* ms */ | |||
#define WAIT_STEP 100 /* ms */ | |||
//#define FORK_TIME_MEASURE | |||
#define USE_VFORK | |||
//#define USE_CLONE | |||
//#define USE_CLONE2 | |||
#if defined(USE_VFORK) | |||
#define FORK vfork | |||
#define FORK_STR "vfork" | |||
#elif defined(USE_CLONE) | |||
#define FORK_STR "clone" | |||
#elif defined(USE_CLONE2) | |||
#define FORK_STR "clone2" | |||
#else | |||
#define FORK fork | |||
#define FORK_STR "fork" | |||
#endif | |||
#include <stdbool.h> | |||
#include <stdio.h> | |||
#include <stdlib.h> | |||
#include <string.h> | |||
#include <sys/types.h> | |||
#include <sys/wait.h> | |||
#if defined(FORK_TIME_MEASURE) | |||
# include <sys/time.h> | |||
#endif | |||
#include <unistd.h> | |||
#if defined(USE_CLONE) || defined(USE_CLONE2) | |||
# include <sched.h> | |||
#endif | |||
#include <fcntl.h> | |||
#include <locale.h> | |||
#include <errno.h> | |||
#include "CarlaNative.h" | |||
struct control | |||
{ | |||
HostDescriptor* host; | |||
bool running; /* true if UI launched and 'exiting' not received */ | |||
bool visible; /* true if 'show' sent */ | |||
int send_pipe; /* the pipe end that is used for sending messages to UI */ | |||
int recv_pipe; /* the pipe end that is used for receiving messages from UI */ | |||
pid_t pid; | |||
}; | |||
static | |||
char * | |||
read_line( | |||
struct control * control_ptr) | |||
{ | |||
ssize_t ret; | |||
char ch; | |||
char buf[100]; | |||
char * ptr; | |||
ptr = buf; | |||
loop: | |||
ret = read(control_ptr->recv_pipe, &ch, 1); | |||
if (ret == 1 && ch != '\n') | |||
{ | |||
*ptr++ = ch; | |||
goto loop; | |||
} | |||
if (ptr != buf) | |||
{ | |||
*ptr = 0; | |||
//printf("recv: \"%s\"\n", buf); | |||
return strdup(buf); | |||
} | |||
return NULL; | |||
} | |||
static | |||
bool | |||
wait_child( | |||
pid_t pid) | |||
{ | |||
pid_t ret; | |||
int i; | |||
if (pid == -1) | |||
{ | |||
fprintf(stderr, "Can't wait for pid -1\n"); | |||
return false; | |||
} | |||
for (i = 0; i < WAIT_ZOMBIE_TIMEOUT / WAIT_STEP; i++) | |||
{ | |||
//printf("waitpid(%d): %d\n", (int)pid, i); | |||
ret = waitpid(pid, NULL, WNOHANG); | |||
if (ret != 0) | |||
{ | |||
if (ret == pid) | |||
{ | |||
//printf("child zombie with pid %d was consumed.\n", (int)pid); | |||
return true; | |||
} | |||
if (ret == -1) | |||
{ | |||
fprintf(stderr, "waitpid(%d) failed: %s\n", (int)pid, strerror(errno)); | |||
return false; | |||
} | |||
fprintf(stderr, "we have waited for child pid %d to exit but we got pid %d instead\n", (int)pid, (int)ret); | |||
return false; | |||
} | |||
//printf("zombie wait %d ms ...\n", WAIT_STEP); | |||
usleep(WAIT_STEP * 1000); /* wait 100 ms */ | |||
} | |||
fprintf( | |||
stderr, | |||
"we have waited for child with pid %d to exit for %.1f seconds and we are giving up\n", | |||
(int)pid, | |||
(float)((float)WAIT_START_TIMEOUT / 1000)); | |||
return false; | |||
} | |||
void | |||
nekoui_run( | |||
struct control * control_ptr) | |||
{ | |||
char * msg; | |||
char * port_index_str; | |||
char * port_value_str; | |||
int index; | |||
float value; | |||
char * locale; | |||
msg = read_line(control_ptr); | |||
if (msg == NULL) | |||
{ | |||
return; | |||
} | |||
locale = strdup(setlocale(LC_NUMERIC, NULL)); | |||
setlocale(LC_NUMERIC, "POSIX"); | |||
if (!strcmp(msg, "port_value")) | |||
{ | |||
port_index_str = read_line(control_ptr); | |||
port_value_str = read_line(control_ptr); | |||
index = atoi(port_index_str); | |||
if (sscanf(port_value_str, "%f", &value) == 1) | |||
{ | |||
//printf("port %d = %f\n", port, value); | |||
control_ptr->host->ui_parameter_changed(control_ptr->host->handle, index, value); | |||
} | |||
else | |||
{ | |||
fprintf(stderr, "failed to convert \"%s\" to float\n", port_value_str); | |||
} | |||
free(port_index_str); | |||
free(port_value_str); | |||
} | |||
else if (!strcmp(msg, "close")) | |||
{ | |||
control_ptr->visible = false; | |||
control_ptr->host->ui_closed(control_ptr->host->handle); | |||
} | |||
else if (!strcmp(msg, "exiting")) | |||
{ | |||
/* for a while wait child to exit, we dont like zombie processes */ | |||
if (!wait_child(control_ptr->pid)) | |||
{ | |||
fprintf(stderr, "force killing misbehaved child %d (exit)\n", (int)control_ptr->pid); | |||
if (kill(control_ptr->pid, SIGKILL) == -1) | |||
{ | |||
fprintf(stderr, "kill() failed: %s (exit)\n", strerror(errno)); | |||
} | |||
else | |||
{ | |||
wait_child(control_ptr->pid); | |||
} | |||
} | |||
control_ptr->running = false; | |||
control_ptr->visible = false; | |||
control_ptr->host->ui_closed(control_ptr->host->handle); | |||
} | |||
else | |||
{ | |||
printf("unknown message: \"%s\"\n", msg); | |||
} | |||
setlocale(LC_NUMERIC, locale); | |||
free(locale); | |||
free(msg); | |||
} | |||
void | |||
nekoui_show( | |||
struct control * control_ptr) | |||
{ | |||
if (control_ptr->visible) | |||
{ | |||
return; | |||
} | |||
write(control_ptr->send_pipe, "show\n", 5); | |||
control_ptr->visible = true; | |||
} | |||
void | |||
nekoui_hide( | |||
struct control * control_ptr) | |||
{ | |||
if (!control_ptr->visible) | |||
{ | |||
return; | |||
} | |||
write(control_ptr->send_pipe, "hide\n", 5); | |||
control_ptr->visible = false; | |||
} | |||
void | |||
nekoui_quit( | |||
struct control * control_ptr) | |||
{ | |||
write(control_ptr->send_pipe, "quit\n", 5); | |||
control_ptr->visible = false; | |||
} | |||
#if defined(FORK_TIME_MEASURE) | |||
static | |||
uint64_t | |||
get_current_time() | |||
{ | |||
struct timeval time; | |||
if (gettimeofday(&time, NULL) != 0) | |||
return 0; | |||
return (uint64_t)time.tv_sec * 1000000 + (uint64_t)time.tv_usec; | |||
} | |||
#define FORK_TIME_MEASURE_VAR_NAME ____t | |||
#define FORK_TIME_MEASURE_VAR uint64_t FORK_TIME_MEASURE_VAR_NAME | |||
#define FORK_TIME_MEASURE_BEGIN FORK_TIME_MEASURE_VAR_NAME = get_current_time() | |||
#define FORK_TIME_MEASURE_END(msg) \ | |||
{ \ | |||
FORK_TIME_MEASURE_VAR_NAME = get_current_time() - FORK_TIME_MEASURE_VAR_NAME; \ | |||
fprintf(stderr, msg ": %llu us\n", (unsigned long long)FORK_TIME_MEASURE_VAR_NAME); \ | |||
} | |||
#else | |||
#define FORK_TIME_MEASURE_VAR | |||
#define FORK_TIME_MEASURE_BEGIN | |||
#define FORK_TIME_MEASURE_END(msg) | |||
#endif | |||
#if defined(USE_CLONE) || defined(USE_CLONE2) | |||
static int clone_fn(void * context) | |||
{ | |||
execvp(*(const char **)context, (char **)context); | |||
return -1; | |||
} | |||
#endif | |||
static | |||
struct control* | |||
nekoui_instantiate( | |||
HostDescriptor* host) | |||
{ | |||
struct control * control_ptr; | |||
char * filename; | |||
int pipe1[2]; /* written by host process, read by plugin UI process */ | |||
int pipe2[2]; /* written by plugin UI process, read by host process */ | |||
char ui_recv_pipe[100]; | |||
char ui_send_pipe[100]; | |||
int oldflags; | |||
FORK_TIME_MEASURE_VAR; | |||
const char * argv[5]; | |||
int ret; | |||
int i; | |||
char ch; | |||
control_ptr = malloc(sizeof(struct control)); | |||
if (control_ptr == NULL) | |||
{ | |||
goto fail; | |||
} | |||
control_ptr->host = host; | |||
if (pipe(pipe1) != 0) | |||
{ | |||
fprintf(stderr, "pipe1 creation failed.\n"); | |||
} | |||
if (pipe(pipe2) != 0) | |||
{ | |||
fprintf(stderr, "pipe2 creation failed.\n"); | |||
} | |||
snprintf(ui_recv_pipe, sizeof(ui_recv_pipe), "%d", pipe1[0]); /* [0] means reading end */ | |||
snprintf(ui_send_pipe, sizeof(ui_send_pipe), "%d", pipe2[1]); /* [1] means writting end */ | |||
// FIXME | |||
const char* bundle_path = "/home/falktx/Personal/FOSS/GIT/Carla/source/backend/native/nekofilter/"; | |||
filename = malloc(strlen(bundle_path) + strlen(UI_EXECUTABLE) + 1); | |||
if (filename == NULL) | |||
{ | |||
goto fail_free_control; | |||
} | |||
strcpy(filename, bundle_path); | |||
strcat(filename, UI_EXECUTABLE); | |||
control_ptr->running = false; | |||
control_ptr->visible = false; | |||
control_ptr->pid = -1; | |||
argv[0] = "python"; | |||
argv[1] = filename; | |||
argv[2] = ui_recv_pipe; /* reading end */ | |||
argv[3] = ui_send_pipe; /* writting end */ | |||
argv[4] = NULL; | |||
FORK_TIME_MEASURE_BEGIN; | |||
#if defined(USE_CLONE) | |||
{ | |||
int stack[8000]; | |||
ret = clone(clone_fn, stack + 4000, CLONE_VFORK, argv); | |||
if (ret == -1) | |||
{ | |||
fprintf(stderr, "clone() failed: %s\n", strerror(errno)); | |||
goto fail_free_control; | |||
} | |||
} | |||
#elif defined(USE_CLONE2) | |||
fprintf(stderr, "clone2() exec not implemented yet\n"); | |||
goto fail_free_control; | |||
#else | |||
ret = FORK(); | |||
switch (ret) | |||
{ | |||
case 0: /* child process */ | |||
/* fork duplicated the handles, close pipe ends that are used by parent process */ | |||
#if !defined(USE_VFORK) | |||
/* it looks we cant do this for vfork() */ | |||
close(pipe1[1]); | |||
close(pipe2[0]); | |||
#endif | |||
execvp(argv[0], (char **)argv); | |||
fprintf(stderr, "exec of UI failed: %s\n", strerror(errno)); | |||
exit(1); | |||
case -1: | |||
fprintf(stderr, "fork() failed to create new process for plugin UI\n"); | |||
goto fail_free_control; | |||
} | |||
#endif | |||
FORK_TIME_MEASURE_END(FORK_STR "() time"); | |||
//fprintf(stderr, FORK_STR "()-ed child process: %d\n", ret); | |||
control_ptr->pid = ret; | |||
/* fork duplicated the handles, close pipe ends that are used by the child process */ | |||
close(pipe1[0]); | |||
close(pipe2[1]); | |||
control_ptr->send_pipe = pipe1[1]; /* [1] means writting end */ | |||
control_ptr->recv_pipe = pipe2[0]; /* [0] means reading end */ | |||
oldflags = fcntl(control_ptr->recv_pipe, F_GETFL); | |||
fcntl(control_ptr->recv_pipe, F_SETFL, oldflags | O_NONBLOCK); | |||
/* wait a while for child process to confirm it is alive */ | |||
//printf("waiting UI start\n"); | |||
i = 0; | |||
loop: | |||
ret = read(control_ptr->recv_pipe, &ch, 1); | |||
switch (ret) | |||
{ | |||
case -1: | |||
if (errno == EAGAIN) | |||
{ | |||
if (i < WAIT_START_TIMEOUT / WAIT_STEP) | |||
{ | |||
//printf("start wait %d ms ...\n", WAIT_STEP); | |||
usleep(WAIT_STEP * 1000); | |||
i++; | |||
goto loop; | |||
} | |||
fprintf( | |||
stderr, | |||
"we have waited for child with pid %d to appear for %.1f seconds and we are giving up\n", | |||
(int)control_ptr->pid, | |||
(float)((float)WAIT_START_TIMEOUT / 1000)); | |||
} | |||
else | |||
{ | |||
fprintf(stderr, "read() failed: %s\n", strerror(errno)); | |||
} | |||
break; | |||
case 1: | |||
if (ch == '\n') | |||
{ | |||
return control_ptr; | |||
} | |||
fprintf(stderr, "read() wrong first char '%c'\n", ch); | |||
break; | |||
default: | |||
fprintf(stderr, "read() returned %d\n", ret); | |||
} | |||
fprintf(stderr, "force killing misbehaved child %d (start)\n", (int)control_ptr->pid); | |||
if (kill(control_ptr->pid, SIGKILL) == -1) | |||
{ | |||
fprintf(stderr, "kill() failed: %s (start)\n", strerror(errno)); | |||
} | |||
/* wait a while child to exit, we dont like zombie processes */ | |||
wait_child(control_ptr->pid); | |||
fail_free_control: | |||
free(control_ptr); | |||
fail: | |||
fprintf(stderr, "lv2fil UI launch failed\n"); | |||
return NULL; | |||
} | |||
void | |||
nekoui_cleanup( | |||
struct control * control_ptr) | |||
{ | |||
//printf("cleanup() called\n"); | |||
free(control_ptr); | |||
} | |||
void nekoui_set_parameter_value( | |||
struct control * control_ptr, | |||
uint32_t index, | |||
float value) | |||
{ | |||
char buf[100]; | |||
int len; | |||
char * locale; | |||
//printf("port_event(%u, %f) called\n", (unsigned int)port_index, *(float *)buffer); | |||
locale = strdup(setlocale(LC_NUMERIC, NULL)); | |||
setlocale(LC_NUMERIC, "POSIX"); | |||
write(control_ptr->send_pipe, "port_value\n", 11); | |||
len = sprintf(buf, "%u\n", (unsigned int)index); | |||
write(control_ptr->send_pipe, buf, len); | |||
len = sprintf(buf, "%.10f\n", value); | |||
write(control_ptr->send_pipe, buf, len); | |||
fsync(control_ptr->send_pipe); | |||
setlocale(LC_NUMERIC, locale); | |||
free(locale); | |||
} | |||
#undef control_ptr |