1 /*
2  * lingot, a musical instrument tuner.
3  *
4  * Copyright (C) 2004-2018  Iban Cereijo.
5  * Copyright (C) 2004-2008  Jairo Chapela.
6 
7  *
8  * This file is part of lingot.
9  *
10  * lingot is free software; you can redistribute it and/or modify
11  * it under the terms of the GNU General Public License as published by
12  * the Free Software Foundation; either version 2 of the License, or
13  * (at your option) any later version.
14  *
15  * lingot is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU General Public License for more details.
19  *
20  * You should have received a copy of the GNU General Public License
21  * along with lingot; if not, write to the Free Software
22  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
23  */
24 
25 #include <assert.h>
26 #include <string.h>
27 #include <stdlib.h>
28 #include <stdio.h>
29 #include <math.h>
30 #include <locale.h>
31 
32 #include "lingot-defs.h"
33 #include "lingot-config.h"
34 #include "lingot-config-scale.h"
35 #include "lingot-msg.h"
36 #include "lingot-i18n.h"
37 
38 #define MAX(a, b) (((a) > (b)) ? (a) : (b))
39 
40 
lingot_config_new(LingotConfig * config)41 void lingot_config_new(LingotConfig* config) {
42 
43 	config->max_nr_iter = 10; // iterations
44 	config->window_type = HAMMING;
45 	config->optimize_internal_parameters = 0;
46 	lingot_config_scale_new(&config->scale);
47 }
48 
lingot_config_destroy(LingotConfig * config)49 void lingot_config_destroy(LingotConfig* config) {
50 	lingot_config_scale_destroy(&config->scale);
51 }
52 
lingot_config_copy(LingotConfig * dst,const LingotConfig * src)53 void lingot_config_copy(LingotConfig* dst, const LingotConfig* src) {
54 	*dst = *src;
55 	lingot_config_scale_new(&dst->scale); // null scale that will be destroyed in the copy below
56 	lingot_config_scale_copy(&dst->scale, &src->scale);
57 }
58 
59 //----------------------------------------------------------------------------
60 
lingot_config_restore_default_values(LingotConfig * config)61 void lingot_config_restore_default_values(LingotConfig* config) {
62 
63 #if defined(DEFAULT_AUDIO_SYSTEM_OSS)
64 	config->audio_system = AUDIO_SYSTEM_OSS;
65 #elif defined(DEFAULT_AUDIO_SYSTEM_JACK)
66 	config->audio_system = AUDIO_SYSTEM_JACK;
67 #elif defined(DEFAULT_AUDIO_SYSTEM_PULSEAUDIO)
68 	config->audio_system = AUDIO_SYSTEM_PULSEAUDIO;
69 #else
70 	config->audio_system = AUDIO_SYSTEM_ALSA;
71 #endif
72 	sprintf(config->audio_dev[AUDIO_SYSTEM_OSS], "%s", "/dev/dsp");
73 	sprintf(config->audio_dev[AUDIO_SYSTEM_ALSA], "%s", "default");
74 	sprintf(config->audio_dev[AUDIO_SYSTEM_JACK], "%s", "default");
75 	sprintf(config->audio_dev[AUDIO_SYSTEM_PULSEAUDIO], "%s", "default");
76 
77 	config->sample_rate = 44100; // Hz
78 	config->oversampling = 21;
79 	config->root_frequency_error = 0.0; // Hz
80 	config->min_frequency = 82.407; // Hz (E2)
81 	config->max_frequency = 329.6276; // Hz (E4)
82 	config->optimize_internal_parameters = 0;
83 
84 	config->fft_size = 512; // samples
85 	config->temporal_window = 0.3; // seconds
86 	config->calculation_rate = 15.0; // Hz
87 	config->visualization_rate = 24.0; // Hz
88 	config->min_overall_SNR = 20.0; // dB
89 
90 	config->peak_number = 8; // peaks
91 	config->peak_half_width = 1; // samples
92 
93 	//--------------------------------------------------------------------------
94 
95 	lingot_config_scale_restore_default_values(&config->scale);
96 	lingot_config_update_internal_params(config);
97 }
98 
99 //----------------------------------------------------------------------------
100 
lingot_config_update_internal_params(LingotConfig * config)101 void lingot_config_update_internal_params(LingotConfig* config) {
102 
103 	// derived parameters.
104 
105 	config->internal_min_frequency = 0.8 * config->min_frequency;
106 	config->internal_max_frequency = 3.1 * config->max_frequency;
107 
108 	if (config->internal_min_frequency < 0) {
109 		config->internal_min_frequency = 0;
110 	}
111 	if (config->internal_max_frequency < 500) {
112 		config->internal_max_frequency = 500;
113 	}
114 	if (config->internal_max_frequency > 20000) {
115 		config->internal_max_frequency = 20000;
116 	}
117 
118 	config->oversampling = floor(
119 			0.5 * config->sample_rate / config->internal_max_frequency);
120 	if (config->oversampling < 1) {
121 		config->oversampling = 1;
122 	}
123 
124 	// TODO: tune this parameters
125 	unsigned int fft_size = 512;
126 	if (config->internal_max_frequency > 5000) {
127 		fft_size = 1024;
128 	}
129 	FLT temporal_window = 1.0 * config->fft_size * config->oversampling
130 			/ config->sample_rate;
131 	if (temporal_window < 0.3) {
132 		temporal_window = 0.3;
133 	}
134 	if (config->optimize_internal_parameters) {
135 		config->fft_size = fft_size;
136 		config->temporal_window = temporal_window;
137 	} else {
138 		// if the governed parameters happen to be the same as the one we would
139 		// suggest, then we will indeed suggest them.
140 		config->optimize_internal_parameters = (config->fft_size == fft_size) &&
141 				(config->temporal_window == temporal_window);
142 	}
143 
144 	config->temporal_buffer_size = (unsigned int) ceil(
145 			config->temporal_window * config->sample_rate
146 			/ config->oversampling);
147 
148 	config->min_SNR = 0.5 * config->min_overall_SNR;
149 	config->peak_half_width = (config->fft_size > 256) ? 2 : 1;
150 
151 	if (config->scale.notes == 1) {
152 		config->scale.max_offset_rounded = 1200.0;
153 	} else {
154 		int i;
155 		FLT max_offset = 0.0;
156 		for (i = 1; i < config->scale.notes; i++) {
157 			max_offset = MAX(max_offset, config->scale.offset_cents[i]
158 					- config->scale.offset_cents[i - 1]);
159 		}
160 		config->scale.max_offset_rounded = max_offset;
161 	}
162 
163 	config->gauge_rest_value = -0.45 * config->scale.max_offset_rounded;
164 }
165 
166