summaryrefslogtreecommitdiffstats
path: root/src/synth_engine_v2.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/synth_engine_v2.c')
-rw-r--r--src/synth_engine_v2.c378
1 files changed, 340 insertions, 38 deletions
diff --git a/src/synth_engine_v2.c b/src/synth_engine_v2.c
index bfd1d4a..ad1be72 100644
--- a/src/synth_engine_v2.c
+++ b/src/synth_engine_v2.c
@@ -4,14 +4,17 @@
#include "filter.h"
#include "control.h"
#include "sound.h"
+#include "midi.h"
#include "osc.h"
+#include <libconfig.h>
#include <string.h>
#include <time.h>
float
gen0(float f, midi_note_t * midi_note, float x, unsigned int sample_rate)
{
+ (void)x; (void)sample_rate;
float sample = osc_sin(midi_note->wvt_index);
midi_note->wvt_index = osc_sin_next(f, midi_note->wvt_index);
return sample;
@@ -20,6 +23,7 @@ gen0(float f, midi_note_t * midi_note, float x, unsigned int sample_rate)
float
gen1(float f, midi_note_t * midi_note, float x, unsigned int sample_rate)
{
+ (void)x; (void)sample_rate;
float sample = osc_saw(midi_note->wvt_index);
midi_note->wvt_index = osc_saw_next(f, midi_note->wvt_index);
return sample;
@@ -28,6 +32,7 @@ gen1(float f, midi_note_t * midi_note, float x, unsigned int sample_rate)
float
gen2(float f, midi_note_t * midi_note, float x, unsigned int sample_rate)
{
+ (void)x; (void)sample_rate;
float sample = osc_weird(midi_note->wvt_index);
midi_note->wvt_index = osc_weird_next(f, midi_note->wvt_index);
return sample;
@@ -36,6 +41,7 @@ gen2(float f, midi_note_t * midi_note, float x, unsigned int sample_rate)
float
gen3(float f, midi_note_t * midi_note, float x, unsigned int sample_rate)
{
+ (void)x; (void)sample_rate;
float sample = osc_tri(midi_note->wvt_index);
midi_note->wvt_index = osc_tri_next(f, midi_note->wvt_index);
return sample;
@@ -44,6 +50,7 @@ gen3(float f, midi_note_t * midi_note, float x, unsigned int sample_rate)
float
gen4(float f, midi_note_t * midi_note, float x, unsigned int sample_rate)
{
+ (void)x; (void)sample_rate;
float sample = osc_sound(midi_note->wvt_index);
midi_note->wvt_index = osc_sound_next(f, midi_note->wvt_index);
return sample;
@@ -52,6 +59,7 @@ gen4(float f, midi_note_t * midi_note, float x, unsigned int sample_rate)
float
gen5(float f, midi_note_t * midi_note, float x, unsigned int sample_rate)
{
+ (void)x; (void)sample_rate;
float sample = osc_digisaw(midi_note->wvt_index);
midi_note->wvt_index = osc_digisaw_next(f, midi_note->wvt_index);
return sample;
@@ -60,6 +68,7 @@ gen5(float f, midi_note_t * midi_note, float x, unsigned int sample_rate)
float
gen6(float f, midi_note_t * midi_note, float x, unsigned int sample_rate)
{
+ (void)x; (void)sample_rate;
float sample = osc_sqr(midi_note->wvt_index);
midi_note->wvt_index = osc_sqr_next(f, midi_note->wvt_index);
return sample;
@@ -106,23 +115,60 @@ notes_active(synth_t *synth)
}
#define CC_GET(name) cc_iget(&synth->cc_##name, frame, FRAMES_PER_BUFFER)
+#define CC_SET(name, value) synth->cc_##name.mod = value - synth->cc_##name.target
float prev_sample = 0.0f;
-float
+#include "biquad_filter.c"
+
+biquad_filter_t biquad = {0};
+
+
+void
do_fliter(synth_t *synth, float *sample, unsigned int sample_rate, int frame)
{
- if (synth->filter) {
- // ALLL THE FILTERS
- float cutoff = CC_GET(cutoff);
- float reso = CC_GET(resonance);
+ synth->f_adsr.a = CC_GET(f_adsr_a);
+ synth->f_adsr.peak = CC_GET(f_adsr_peak);
+ synth->f_adsr.d = CC_GET(f_adsr_d);
+ synth->f_adsr.s = CC_GET(f_adsr_s);
+ synth->f_adsr.r = CC_GET(f_adsr_r);
+
+ // ALLL THE FILTERS
+ float cutoff = CC_GET(cutoff);
+ float reso = CC_GET(resonance);
+
+ if (synth->f_adsr_enabled) {
+ midi_note_t *note;
+ if (synth->midi_active_n != 0) {
+ float latest = 0;
+ for (int i = 0; i < synth->midi_active_n; i++) {
+ // reverse this and set latest to a big number for the first note played to take precedence
+ if (synth->midi_active[i]->noteOn > latest) {
+ latest = synth->midi_active[i]->noteOn;
+ note = synth->midi_active[i];
+ }
+ }
+
+ cutoff = 50 + cutoff * fix_adsr(&synth->f_adsr,
+ note->noteOn,
+ note->noteOff,
+ note->elapsed,
+ note->noteOffSample);
+ }
+ }
+ if (synth->filter) {
if (cutoff == 0) cutoff = 0.001;
lpf_update(reso, cutoff, sample_rate);
*sample = lpf_filter(*sample);
- update_bw_low_pass_filter(synth->fff, SAMPLE_RATE, cutoff, reso);
- *sample = bw_low_pass(synth->fff, *sample);
+ /* update_bw_low_pass_filter(synth->fff, SAMPLE_RATE, cutoff, reso); */
+ /* *sample = bw_low_pass(synth->fff, *sample); */
+ }
+ if (synth->biquad) {
+ //if (synth->cc_cutoff.mod || synth->cc_resonance.mod) //RUN ONLY WHEN THERE ARE CHANGES
+ biquad_calculate_coefficients(&biquad, cutoff, reso, sample_rate, synth->biquad_type);
+ *sample = biquad_process(&biquad, *sample);
}
}
@@ -161,6 +207,19 @@ get_max_sample(synth_t *synth, int test_size)
return max;
}
+# include <stdint.h> // uint32_t
+
+float Q_rsqrt(float number)
+{
+ union {
+ float f;
+ uint32_t i;
+ } conv = { .f = number };
+ conv.i = 0x5f3759df - (conv.i >> 1);
+ conv.f *= 1.5F - (number * 0.5F * conv.f * conv.f);
+ return conv.f;
+}
+
float
make_sample(synth_t * synth, unsigned int sample_rate, int frame)
{
@@ -174,7 +233,7 @@ make_sample(synth_t * synth, unsigned int sample_rate, int frame)
rms += synth->midi_active[i]->velocity * synth->midi_active[i]->velocity;
}
- rms = sqrt(rms / (float)synth->midi_active_n);
+ rms = 1.0 / Q_rsqrt(rms / (float)synth->midi_active_n);
//float max = get_max_sample(synth, 20);
synth->adsr.a = CC_GET(adsr_a);
@@ -202,15 +261,23 @@ make_sample(synth_t * synth, unsigned int sample_rate, int frame)
sample_rate);
}
+
/* filter */
do_fliter(synth, &sample, sample_rate, frame);
+
sample = CC_GET(gain) * sample;
// band stop for high freqs
//sample = bw_band_stop(synth->fff2, sample);
-
- if (synth->clamp) sample = clamp(sample, -1, 1);
+
+ //if (synth->clamp) sample = clamp(sample, -1, 1);
+
+ // autogain
+ if (synth->autogain && (sample >= 1 || sample <= -1)) {
+ synth->cc_gain.target *= 0.999;
+ }
+
//printf("CLICK! %f\n", fabsf(prev_sample) - fabsf(sample));
//if (fabsf(fabsf(prev_sample) - fabsf(sample)) > 0.03) printf("CLICK! (diff: %f)\n", fabsf(prev_sample) - fabsf(sample));
prev_sample = sample;
@@ -232,6 +299,7 @@ increment_synth(synth_t *synth)
{
synth->lfo.elapsed++;
synth->adsr.elapsed++;
+ synth->f_adsr.elapsed++;
for (int i = 0; i < synth->midi_active_n; i++) {
if (synth->midi_active[i])
@@ -239,23 +307,28 @@ increment_synth(synth_t *synth)
}
}
+float prev = 0;
+
void
-get_frame(void *outputBuffer, synth_t *synth, int i)
+get_frame(void *outputBuffer, synth_t *synth, int frame)
{
- float *out = (float*)outputBuffer + 2 * i;
- float s = 0.0f;
+ float *out = (float*)outputBuffer + (2 * frame);
+ float sample = 0.0f;
if (!notes_active(synth)) {
+ synth->f_adsr.elapsed = 0;
synth->active = 0;
+ // auto gain test
+ //synth->cc_gain.target = 1;
}
if (!synth->delay) {
synth->counter = 0;
}
- s = make_sample(synth, SAMPLE_RATE, i);
+ sample = make_sample(synth, SAMPLE_RATE, frame);
synth->counter++;
- if (synth->counter >= (int)(synth->cc_del_time.target * SAMPLE_RATE)) {
+ if (synth->counter >= (unsigned long long)(synth->cc_del_time.target * SAMPLE_RATE)) {
int idx = (synth->deli - (int)(synth->cc_del_time.target * SAMPLE_RATE)) % (SAMPLE_RATE * 10);
float tmp;
if (idx >= 0) {
@@ -264,18 +337,60 @@ get_frame(void *outputBuffer, synth_t *synth, int i)
tmp = synth->del[SAMPLE_RATE * 10 + idx];
}
- s = clamp(s + synth->cc_del_feedback.target * tmp, -1, 1);
+ sample = clamp(sample + synth->cc_del_feedback.target * tmp, -1, 1);
}
- add_to_delay(synth, s);
- *out++ = s;
- *out++ = s;
+ add_to_delay(synth, sample);
+
+
+
+ //sample = clamp(sample, -1, 1);
+
+ *out++ = sample;
+ *out++ = sample;
+
+ if (sample > 1.0f || sample < -1.0f)
+ printf("%f\n", sample);
+ if (prev != 0.0f && fabs(prev - sample) > 0.5f) {
+ printf("%.2f --> %.2f\n", prev, sample);
+ }
+ prev = sample;
// move time
increment_synth(synth);
// viz
- PaUtil_WriteRingBuffer(&synth->viz.wave_buffer, &s, 1);
+ PaUtil_WriteRingBuffer(&synth->viz.wave_buffer, &sample, 1);
+}
+
+/* void */
+/* smooth_buffer1(float *buffer) */
+/* { */
+/* return; */
+/* } */
+void smooth_buffer(float *buffer, int frames_per_buffer, float smooth_factor) {
+ if (smooth_factor < 0.0f || smooth_factor > 1.0f) {
+ printf("Invalid smooth factor. It should be between 0 and 1.\n");
+ return;
+ }
+
+ float prev_sample_ch1 = buffer[0]; // First sample for channel 1
+ float prev_sample_ch2 = buffer[1]; // First sample for channel 2
+
+ for (int i = 0; i < frames_per_buffer; i++) {
+ int ch1_index = 2 * i; // Index for channel 1
+ int ch2_index = 2 * i + 1; // Index for channel 2
+
+ // Smooth channel 1
+ buffer[ch1_index] = (1.0f - smooth_factor) * buffer[ch1_index] +
+ smooth_factor * prev_sample_ch1;
+ prev_sample_ch1 = buffer[ch1_index];
+
+ // Smooth channel 2
+ buffer[ch2_index] = (1.0f - smooth_factor) * buffer[ch2_index] +
+ smooth_factor * prev_sample_ch2;
+ prev_sample_ch2 = buffer[ch2_index];
+ }
}
@@ -292,7 +407,6 @@ sound_gen(const void *inputBuffer, void *outputBuffer,
if (!synth->sound_active) return 0; //paContinue;
float buffer[2 * FRAMES_PER_BUFFER];
- float buffer2[2 * FRAMES_PER_BUFFER];
(void) timeInfo;
(void) statusFlags;
@@ -305,14 +419,15 @@ sound_gen(const void *inputBuffer, void *outputBuffer,
cc_prep(synth->ccs[i]);
}
// fill buffer
- for( unsigned long i=0; i<framesPerBuffer; i++ ) {
+ for( unsigned long frame=0; frame<framesPerBuffer; frame++ ) {
// use iget inside
- get_frame(buffer, synth, i);
+ get_frame(buffer, synth, frame);
}
+ smooth_buffer(buffer, framesPerBuffer, 0.1f);
+
// output buffer
for( unsigned long i=0; i<framesPerBuffer * 2; i += 2 ) {
- // use iget inside
*out++ = buffer[i];
*out++ = buffer[i+1];
}
@@ -330,13 +445,6 @@ sound_gen(const void *inputBuffer, void *outputBuffer,
return paContinue;
}
-void
-m_init_synth(synth_t * synth)
-{
- synth = (synth_t *)malloc(sizeof(synth_t));
-
-}
-
synth_t *
init_synth(void)
{
@@ -345,8 +453,9 @@ init_synth(void)
synth->cci = 0;
// CC(SYNTH, NAME, MIN, MAX, STEP, DEF)
- CC(synth->cc_cutoff, "cutoff", 10, 22000, 30, 5000);
- CC(synth->cc_resonance, "resonance", 1, 10, .02, 1);
+ CC(synth->cc_cutoff, "cutoff", 50, 22000, 30, 5000);
+ //CC(synth->cc_resonance, "resonance", 1, 10, .02, 1);
+ CC(synth->cc_resonance, "resonance", 0.01, 10, .02, 0.5);
CC(synth->cc_lfo_freq, "lfo_freq", 1, 1000, 2, 1);
CC(synth->cc_lfo_amp, "lfo_amp", 0, 1, .01f, 0);
CC(synth->cc_pitch, "pitch", -3, 4, 0.01f, 1);
@@ -359,7 +468,14 @@ init_synth(void)
CC(synth->cc_del_feedback, "feedback", 0, 1, 0.01f, 0.5f);
CC(synth->cc_gain, "gain", 0, 1, 0.01f, 0.5f);
- //synth->modi = 0;
+ CC(synth->cc_f_adsr_a, "fattack", 0, 3, 0.01f, 0.00);
+ CC(synth->cc_f_adsr_peak, "fpeak", 0, 1, 0.01f, 1.00);
+ CC(synth->cc_f_adsr_d, "fdecay", 0, 2, 0.01f, 0.3);
+ CC(synth->cc_f_adsr_s, "fsustain", 0, 1.0f, 0.01f, 0.7f);
+ CC(synth->cc_f_adsr_r, "frelease", 0, 5, 0.01f, 0.2f);
+
+ // synth->modi = 0;
+ synth->autogain = 1;
synth->x = 1;
@@ -370,6 +486,13 @@ init_synth(void)
synth->adsr.r = 0.4;
synth->adsr.elapsed = 0;
+ synth->f_adsr.a = 0.00001f;
+ synth->f_adsr.peak = 1.0f;
+ synth->f_adsr.d = 0.3;
+ synth->f_adsr.s = 0.7;
+ synth->f_adsr.r = 0.4;
+ synth->f_adsr.elapsed = 0;
+
synth->lfo.freq = 1.0f;
synth->lfo.amp = 0.0f;
synth->lfo.elapsed = 0;
@@ -394,9 +517,12 @@ init_synth(void)
synth->delay = 0;
synth->del = (float *) calloc(sizeof(float), SAMPLE_RATE * 30);
synth->deli = 0;
- synth->counter;
+ synth->counter = 0;
+ synth->f_adsr_enabled = 0;
synth->filter = 1;
+ synth->biquad = 0;
+ synth->biquad_type = 'l';
synth->clamp = 1;
synth->gen[0] = gen0;
@@ -414,9 +540,6 @@ init_synth(void)
synth->fff = create_bw_low_pass_filter(2, SAMPLE_RATE, 400);
synth->fff2 = create_bw_band_stop_filter(8, SAMPLE_RATE, 15000, 22000);
- synth->sound_active = 0;
- init_sound(synth, sound_gen);
-
synth->viz.rate_divider = 15;
// for (int i = 0; i < RING_SIZE; i++) synth->viz.wave_buffer_data[i] = 0;
synth->viz.wave_buffer_data = (float *)calloc(sizeof(float), RING_SIZE);
@@ -441,6 +564,16 @@ init_synth(void)
synth->wvt_pos = 0;
+
+
+ synth->sound_active = 0;
+ synth->soundcard_id = get_soundcard_id("default");
+ init_sound(synth, sound_gen, synth->soundcard_id);
+
+ synth->midi = (midi_t *)malloc(sizeof(midi_t));
+ synth->midi_device_id = get_midi_device_id("Midi Through Port-0");
+ init_midi(synth->midi, synth);
+
return synth;
}
@@ -448,6 +581,7 @@ void
free_synth(synth_t * synth)
{
destroy_sound(synth);
+ terminate_midi(synth->midi);
free(synth->viz.wave_buffer_data);
free(synth->viz.fft_buffer_data);
@@ -456,6 +590,8 @@ free_synth(synth_t * synth)
free(synth->viz.fft_input_buffer);
free(synth->viz.fft_output_buffer);
free(synth->viz.fft_smooth_buffer);
+
+ free(synth->midi);
free_bw_low_pass(synth->fff);
free_bw_band_stop(synth->fff2);
@@ -463,3 +599,169 @@ free_synth(synth_t * synth)
free(synth->del);
free(synth);
}
+
+void
+change_soundcard(synth_t *synth)
+{
+ destroy_sound(synth);
+ synth->sound_active = 0;
+ init_sound(synth, sound_gen, synth->soundcard_id);
+}
+
+void
+change_midi_device(synth_t *synth)
+{
+ terminate_midi(synth->midi);
+ free(synth->midi);
+
+ synth->midi = (midi_t *)malloc(sizeof(midi_t));
+ init_midi(synth->midi, synth);
+}
+
+int
+load_synth(synth_t *synth, const char *path)
+{
+ (void)path;
+ config_t cfg;
+ const char *str;
+ double FLOAT;
+
+ config_init(&cfg);
+
+ /* Read the file. If there is an error, report it and exit. */
+ if(! config_read_file(&cfg, "TEST.cfg"))
+ {
+ fprintf(stderr, "%s:%d - %s\n", config_error_file(&cfg),
+ config_error_line(&cfg), config_error_text(&cfg));
+ config_destroy(&cfg);
+ return(EXIT_FAILURE);
+ }
+
+ /* Get the store name. */
+ if(config_lookup_string(&cfg, "synth.name", &str))
+ printf("LOADING: %s ----\n---\n", str);
+ else
+ fprintf(stderr, "No 'synth.name' setting in configuration file.\n");
+
+ config_lookup_int(&cfg, "synth.generator", &synth->geni);
+
+ config_lookup_float(&cfg, "synth.adsr.a", &FLOAT);
+ synth->cc_adsr_a.target = FLOAT;
+ config_lookup_float(&cfg, "synth.adsr.peak", &FLOAT);
+ synth->cc_adsr_peak.target = FLOAT;
+ config_lookup_float(&cfg, "synth.adsr.d", &FLOAT);
+ synth->cc_adsr_d.target = FLOAT;
+ config_lookup_float(&cfg, "synth.adsr.s", &FLOAT);
+ synth->cc_adsr_s.target = FLOAT;
+ config_lookup_float(&cfg, "synth.adsr.r", &FLOAT);
+ synth->cc_adsr_r.target = FLOAT;
+
+ config_lookup_int(&cfg, "synth.delay.enable", &synth->delay);
+ config_lookup_float(&cfg, "synth.delay.time", &FLOAT);
+ synth->cc_del_time.target = FLOAT;
+ config_lookup_float(&cfg, "synth.delay.feedback", &FLOAT);
+ synth->cc_del_feedback.target = FLOAT;
+
+ config_lookup_int(&cfg, "synth.filter.enable", &synth->filter);
+ config_lookup_float(&cfg, "synth.filter.cutoff", &FLOAT);
+ synth->cc_cutoff.target = FLOAT;
+ config_lookup_float(&cfg, "synth.filter.resonance", &FLOAT);
+ synth->cc_resonance.target = FLOAT;
+
+ config_lookup_float(&cfg, "synth.lfo.freq", &FLOAT);
+ synth->cc_lfo_freq.target = FLOAT;
+ config_lookup_float(&cfg, "synth.lfo.amp", &FLOAT);
+ synth->cc_lfo_amp.target = FLOAT;
+
+ config_lookup_int(&cfg, "synth.autogain", &synth->autogain);
+ config_lookup_float(&cfg, "synth.gain", &FLOAT);
+ synth->cc_gain.target = FLOAT;
+
+ config_destroy(&cfg);
+ return(EXIT_SUCCESS);
+}
+
+int
+save_synth(synth_t *synth, const char *path)
+{
+ (void)path;
+
+ static const char *output_file = "TEST.cfg";
+
+ config_t cfg;
+ config_setting_t *root, *setting, *group, *adsr, *delay, *lfo, *filter;
+
+ config_init(&cfg);
+ root = config_root_setting(&cfg);
+
+ /* Add some settings to the configuration. */
+ group = config_setting_add(root, "synth", CONFIG_TYPE_GROUP);
+
+ setting = config_setting_add(group, "name", CONFIG_TYPE_STRING);
+ config_setting_set_string(setting, "example synth name");
+
+ setting = config_setting_add(group, "generator", CONFIG_TYPE_INT);
+ config_setting_set_int(setting, synth->geni);
+
+ adsr = config_setting_add(group, "adsr", CONFIG_TYPE_GROUP);
+ setting = config_setting_add(adsr, "a", CONFIG_TYPE_FLOAT);
+ config_setting_set_float(setting, synth->cc_adsr_a.target);
+ setting = config_setting_add(adsr, "peak", CONFIG_TYPE_FLOAT);
+ config_setting_set_float(setting, synth->cc_adsr_peak.target);
+ setting = config_setting_add(adsr, "d", CONFIG_TYPE_FLOAT);
+ config_setting_set_float(setting, synth->cc_adsr_d.target);
+ setting = config_setting_add(adsr, "s", CONFIG_TYPE_FLOAT);
+ config_setting_set_float(setting, synth->cc_adsr_s.target);
+ setting = config_setting_add(adsr, "r", CONFIG_TYPE_FLOAT);
+ config_setting_set_float(setting, synth->cc_adsr_r.target);
+
+ delay = config_setting_add(group, "delay", CONFIG_TYPE_GROUP);
+ setting = config_setting_add(delay, "enable", CONFIG_TYPE_INT);
+ config_setting_set_int(setting, synth->delay);
+ setting = config_setting_add(delay, "time", CONFIG_TYPE_FLOAT);
+ config_setting_set_float(setting, synth->cc_del_time.target);
+ setting = config_setting_add(delay, "feedback", CONFIG_TYPE_FLOAT);
+ config_setting_set_float(setting, synth->cc_del_feedback.target);
+
+ filter = config_setting_add(group, "filter", CONFIG_TYPE_GROUP);
+ setting = config_setting_add(filter, "enable", CONFIG_TYPE_INT);
+ config_setting_set_int(setting, synth->filter);
+ setting = config_setting_add(filter, "cutoff", CONFIG_TYPE_FLOAT);
+ config_setting_set_float(setting, synth->cc_cutoff.target);
+ setting = config_setting_add(filter, "resonance", CONFIG_TYPE_FLOAT);
+ config_setting_set_float(setting, synth->cc_resonance.target);
+
+ lfo = config_setting_add(group, "lfo", CONFIG_TYPE_GROUP);
+ setting = config_setting_add(lfo, "freq", CONFIG_TYPE_FLOAT);
+ config_setting_set_float(setting, synth->cc_lfo_freq.target);
+ setting = config_setting_add(lfo, "amp", CONFIG_TYPE_FLOAT);
+ config_setting_set_float(setting, synth->cc_lfo_amp.target);
+
+ setting = config_setting_add(group, "autogain", CONFIG_TYPE_INT);
+ config_setting_set_int(setting, synth->autogain);
+ setting = config_setting_add(group, "gain", CONFIG_TYPE_FLOAT);
+ config_setting_set_float(setting, synth->cc_gain.target);
+
+
+ /* array = config_setting_add(root, "numbers", CONFIG_TYPE_ARRAY); */
+
+ /* for(i = 0; i < 10; ++i) */
+ /* { */
+ /* setting = config_setting_add(array, NULL, CONFIG_TYPE_INT); */
+ /* config_setting_set_int(setting, 10 * i); */
+ /* } */
+
+ /* Write out the new configuration. */
+ if(! config_write_file(&cfg, output_file))
+ {
+ fprintf(stderr, "Error while writing file.\n");
+ config_destroy(&cfg);
+ return(EXIT_FAILURE);
+ }
+
+ fprintf(stderr, "New configuration successfully written to: %s\n",
+ output_file);
+
+ config_destroy(&cfg);
+ return(EXIT_SUCCESS);
+}