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