1 // Licensed GNU LGPL v3 or later: http://www.gnu.org/licenses/lgpl.html
2
3 #include "smmain.hh"
4 #include "smrandom.hh"
5 #include "smencoder.hh"
6 #include "smlivedecoder.hh"
7 #include "smfft.hh"
8 #include "config.h"
9
10 #if SPECTMORPH_HAVE_BSE
11 #include <bse/bsemathsignal.hh>
12 #include <bse/gsldatautils.hh>
13 #endif
14
15 #include <vector>
16 #include <assert.h>
17 #include <stdio.h>
18 #include <unistd.h>
19
20 using namespace SpectMorph;
21
22 using std::vector;
23
24 size_t
make_odd(size_t n)25 make_odd (size_t n)
26 {
27 if (n & 1)
28 return n;
29 return n - 1;
30 }
31
32 void
encode_decode(vector<float> & audio_in,vector<float> & audio_out)33 encode_decode (vector<float>& audio_in, vector<float>& audio_out)
34 {
35 EncoderParams enc_params;
36 enc_params.mix_freq = 44100;
37 enc_params.zeropad = 4;
38 enc_params.fundamental_freq = 440;
39 enc_params.frame_size_ms = 40;
40 enc_params.frame_step_ms = enc_params.frame_size_ms / 4.0;
41 enc_params.frame_size = make_odd (enc_params.mix_freq * 0.001 * enc_params.frame_size_ms);
42 enc_params.frame_step = enc_params.mix_freq * 0.001 * enc_params.frame_step_ms;
43
44 /* compute block size from frame size (smallest 2^k value >= frame_size) */
45 uint64 block_size = 1;
46 while (block_size < enc_params.frame_size)
47 block_size *= 2;
48 enc_params.block_size = block_size;
49 vector<float> window (block_size);
50
51 for (guint i = 0; i < window.size(); i++)
52 {
53 if (i < enc_params.frame_size)
54 window[i] = window_cos (2.0 * i / enc_params.frame_size - 1.0);
55 else
56 window[i] = 0;
57 }
58 enc_params.window = window;
59
60 Encoder encoder (enc_params);
61
62 WavData wav_data (audio_in, 1, enc_params.mix_freq, 32);
63
64 const char *sm_file = "testnoise.tmp.sm";
65 encoder.encode (wav_data, 0, 1, /*attack*/ false, /*sines*/ false);
66 encoder.save (sm_file);
67
68 WavSet wav_set;
69 LiveDecoder decoder (&wav_set);
70
71 WavSetWave new_wave;
72 new_wave.midi_note = 60; // doesn't matter
73 new_wave.channel = 0;
74 new_wave.path = sm_file;
75 wav_set.waves.push_back (new_wave);
76
77 wav_set.save ("testnoise.tmp.smset", true);
78
79 wav_set = WavSet();
80 Error error = wav_set.load ("testnoise.tmp.smset");
81 assert (!error);
82
83 float freq = 440;
84 decoder.retrigger (0, freq, 127, enc_params.mix_freq);
85 decoder.process (audio_out.size(), nullptr, &audio_out[0]);
86 }
87
88 void
avg_spectrum(const char * label,vector<float> & signal)89 avg_spectrum (const char *label, vector<float>& signal)
90 {
91 const size_t block_size = 2048;
92 size_t offset = 0;
93
94 vector<float> avg (block_size / 2 + 1);
95 vector<float> window (block_size);
96
97 for (guint i = 0; i < window.size(); i++)
98 window[i] = window_cos (2.0 * i / block_size - 1.0);
99
100 float *in = FFT::new_array_float (block_size);
101 float *out = FFT::new_array_float (block_size + 2);
102
103 while (offset + block_size < signal.size())
104 {
105 std::copy (signal.begin() + offset, signal.begin() + offset + block_size, in);
106 for (size_t i = 0; i < block_size; i++)
107 in[i] *= window[i];
108
109 FFT::fftar_float (block_size, in, out);
110
111 out[block_size] = out[1];
112 out[block_size+1] = 0;
113 out[1] = 0;
114
115 for (size_t d = 0; d < block_size + 2; d += 2)
116 avg[d/2] += out[d] * out[d] + out[d+1] * out[d+1];
117 offset += block_size / 4;
118 }
119
120 for (size_t i = 0; i < avg.size(); i++)
121 printf ("%s %g %g\n", label, i * 44100.0 / block_size, avg[i]);
122 }
123
124 void
highpass(vector<float> & audio_in,vector<float> & audio_out,double cutoff_freq)125 highpass (vector<float>& audio_in, vector<float>& audio_out, double cutoff_freq)
126 {
127 #if !SPECTMORPH_HAVE_BSE
128 g_printerr ("testnoise: highpass: not supported, need libbse to do this\n");
129 g_assert_not_reached();
130 #else
131 GslDataHandle *dhandle = gsl_data_handle_new_mem (1, 32, 44100, 440, audio_in.size(), &audio_in[0], NULL);
132 Bse::Error error = gsl_data_handle_open (dhandle);
133 assert (error == 0);
134
135 GslDataHandle *highpass_dhandle = bse_data_handle_new_fir_highpass (dhandle, cutoff_freq, 64);
136 error = gsl_data_handle_open (highpass_dhandle);
137 assert (error == 0);
138
139 GslDataPeekBuffer peek_buffer = { 0, };
140 audio_out.resize (audio_in.size());
141 for (size_t i = 0; i < audio_out.size(); i++)
142 audio_out[i] = gsl_data_handle_peek_value (highpass_dhandle, i, &peek_buffer);
143 #endif
144 }
145
146 void
energy(vector<float> & audio,const char * label)147 energy (vector<float>& audio, const char *label)
148 {
149 double e = 0;
150 for (size_t i = 0; i < audio.size(); i++)
151 e += audio[i] * audio[i];
152
153 printf ("%s %g\n", label, e);
154 }
155
156 int
main(int argc,char ** argv)157 main (int argc, char **argv)
158 {
159 Random random;
160
161 Main main (&argc, &argv);
162
163 vector<float> noise (44100 * 5);
164 vector<float> audio_out (noise.size());
165
166 for (size_t i = 0; i < noise.size(); i++)
167 noise[i] = random.random_double_range (-0.5, 0.5);
168
169 encode_decode (noise, audio_out);
170
171 energy (noise, "white-noise-in-energy");
172 energy (audio_out, "white-noise-out-energy");
173
174 avg_spectrum ("white-noise-in", noise);
175 avg_spectrum ("white-noise-out", audio_out);
176
177 vector<float> hp_noise;
178 highpass (noise, hp_noise, 3000);
179 encode_decode (hp_noise, audio_out);
180
181 energy (hp_noise, "hp-noise-in-energy");
182 energy (audio_out, "hp-noise-out-energy");
183
184 avg_spectrum ("hp-noise-in", hp_noise);
185 avg_spectrum ("hp-noise-out", audio_out);
186
187 unlink ("testnoise.tmp.sm");
188 unlink ("testnoise.tmp.smset");
189 }
190