1 // Copyright 2014 Emilie Gillet.
2 //
3 // Author: Emilie Gillet (emilie.o.gillet@gmail.com)
4 //
5 // Permission is hereby granted, free of charge, to any person obtaining a copy
6 // of this software and associated documentation files (the "Software"), to deal
7 // in the Software without restriction, including without limitation the rights
8 // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 // copies of the Software, and to permit persons to whom the Software is
10 // furnished to do so, subject to the following conditions:
11 //
12 // The above copyright notice and this permission notice shall be included in
13 // all copies or substantial portions of the Software.
14 //
15 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21 // THE SOFTWARE.
22 //
23 // See http://creativecommons.org/licenses/MIT/ for more information.
24 //
25 // -----------------------------------------------------------------------------
26 
27 
28 #include <cassert>
29 #include <cmath>
30 #include <cstdlib>
31 #include <cstring>
32 #include <vector>
33 #include <xmmintrin.h>
34 
35 #include "clouds/dsp/granular_processor.h"
36 #include "clouds/resources.h"
37 
38 using namespace clouds;
39 using namespace std;
40 using namespace stmlib;
41 
42 const size_t kSampleRate = 32000;
43 const size_t kBlockSize = 32;
44 
write_wav_header(FILE * fp,int num_samples,int num_channels)45 void write_wav_header(FILE* fp, int num_samples, int num_channels) {
46   uint32_t l;
47   uint16_t s;
48 
49   fwrite("RIFF", 4, 1, fp);
50   l = 36 + num_samples * 2 * num_channels;
51   fwrite(&l, 4, 1, fp);
52   fwrite("WAVE", 4, 1, fp);
53 
54   fwrite("fmt ", 4, 1, fp);
55   l = 16;
56   fwrite(&l, 4, 1, fp);
57   s = 1;
58   fwrite(&s, 2, 1, fp);
59   s = num_channels;
60   fwrite(&s, 2, 1, fp);
61   l = kSampleRate;
62   fwrite(&l, 4, 1, fp);
63   l = static_cast<uint32_t>(kSampleRate) * 2 * num_channels;
64   fwrite(&l, 4, 1, fp);
65   s = 2 * num_channels;
66   fwrite(&s, 2, 1, fp);
67   s = 16;
68   fwrite(&s, 2, 1, fp);
69 
70   fwrite("data", 4, 1, fp);
71   l = num_samples * 2 * num_channels;
72   fwrite(&l, 4, 1, fp);
73 }
74 
TestDSP()75 void TestDSP() {
76   size_t duration = 19;
77 
78   FILE* fp_out = fopen("clouds.wav", "wb");
79   FILE* fp_in = fopen("audio_samples/kettel_32k.wav", "rb");
80 
81   size_t remaining_samples = kSampleRate * duration;
82   write_wav_header(fp_out, remaining_samples, 2);
83   fseek(fp_in, 48, SEEK_SET);
84 
85   uint8_t large_buffer[118784];
86   uint8_t small_buffer[65536 - 128];
87 
88   GranularProcessor processor;
89   processor.Init(
90       &large_buffer[0], sizeof(large_buffer),
91       &small_buffer[0],sizeof(small_buffer));
92 
93   processor.set_num_channels(2);
94   processor.set_low_fidelity(false);
95   processor.set_playback_mode(PLAYBACK_MODE_LOOPING_DELAY);
96 
97   Parameters* p = processor.mutable_parameters();
98 
99   size_t block_counter = 0;
100   float phase_ = 0.0f;
101   bool synthetic = true;
102   processor.Prepare();
103   float pot_noise = 0.0f;
104   while (remaining_samples) {
105     uint16_t tri = (remaining_samples * 2);
106     tri = tri > 32767 ? 65535 - tri : tri;
107     float triangle = tri / 32768.0f;
108 
109     p->gate = false;
110     p->trigger = false;
111     p->freeze = true && (block_counter & 2047) > 1024;
112     pot_noise += 0.05f * ((Random::GetSample() / 32768.0f) * 0.00f - pot_noise);
113     p->position = triangle * 0.0f + 0.00f;
114     p->size = 0.5f;
115     p->pitch = -7.0f + (triangle > 0.5f ? 1.0f : 0.0f) * 0.0f;
116     p->density = 0.0f;
117     p->texture = 0.5f;
118     p->feedback = 0.0f;
119     p->dry_wet = 1.0f;
120     p->reverb = 0.0f;
121     p->stereo_spread = 0.0f;
122 
123     ++block_counter;
124     ShortFrame input[kBlockSize];
125     ShortFrame output[kBlockSize];
126 
127     if (synthetic) {
128       for (size_t i = 0; i < kBlockSize; ++i) {
129         phase_ += 400.0f / kSampleRate; // (block_counter & 512 ? 110.0f : 220.0f) / kSampleRate;
130         while (phase_ >= 1.0) {
131           phase_ -= 1.0;
132         }
133         input[i].l = 16384.0f * sinf(phase_ * M_PI * 2);
134         // input[i].r = 32768.0f * (phase_ - 0.5);
135         input[i].r = input[i].l;
136       }
137       remaining_samples -= kBlockSize;
138     } else {
139       if (fread(
140               input,
141               sizeof(ShortFrame),
142               kBlockSize,
143               fp_in) != kBlockSize) {
144         break;
145       }
146       remaining_samples -= kBlockSize;
147     }
148     processor.Process(input, output, kBlockSize);
149     processor.Prepare();
150     fwrite(output, sizeof(ShortFrame), kBlockSize, fp_out);
151   }
152   fclose(fp_out);
153   fclose(fp_in);
154 }
155 
TestGrainSize()156 void TestGrainSize() {
157   for (int32_t _p = 0; _p < 3; _p++) {
158     for (int32_t _s = 0; _s < 3; _s++) {
159       for (int32_t _pi = 0; _pi < 3; _pi++) {
160   size_t duration = 19;
161   char name[80];
162   sprintf(name, "clouds_%d%d%d.wav", _p, _s, _pi);
163   FILE* fp_out = fopen(name, "wb");
164   FILE* fp_in = fopen("audio_samples/kettel_32k.wav", "rb");
165 
166   size_t remaining_samples = kSampleRate * duration;
167   write_wav_header(fp_out, remaining_samples, 2);
168   fseek(fp_in, 48, SEEK_SET);
169 
170   uint8_t large_buffer[118784];
171   uint8_t small_buffer[65536];
172 
173   GranularProcessor processor;
174   processor.Init(
175       &large_buffer[0], sizeof(large_buffer),
176       &small_buffer[0],sizeof(small_buffer));
177 
178   processor.set_num_channels(2);
179   processor.set_low_fidelity(false);
180   processor.set_playback_mode(PLAYBACK_MODE_GRANULAR);
181 
182   Parameters* p = processor.mutable_parameters();
183 
184   size_t block_counter = 0;
185   processor.Prepare();
186   while (remaining_samples) {
187     p->trigger = false;
188     p->freeze = (block_counter & 1023) > 512;
189     p->position = _p * 0.5f;
190     p->size = _s * 0.5f;
191     p->pitch = _pi * 24.0f - 24.0f;
192     p->density = 0.75f;
193     p->texture = 0.5f;
194     p->feedback = 0.0f;
195     p->dry_wet = 1.0f;
196     p->reverb = 0.0f;
197     p->stereo_spread = 0.0f;
198 
199     ++block_counter;
200     ShortFrame input[kBlockSize];
201     ShortFrame output[kBlockSize];
202 
203     uint16_t tri = (remaining_samples / 4);
204     tri = tri > 32767 ? 65535 - tri : tri;
205 
206     if (fread(
207             input,
208             sizeof(ShortFrame),
209             kBlockSize,
210             fp_in) != kBlockSize) {
211       break;
212     }
213     remaining_samples -= kBlockSize;
214     processor.Process(input, output, kBlockSize);
215     processor.Prepare();
216     fwrite(output, sizeof(ShortFrame), kBlockSize, fp_out);
217   }
218 
219   fclose(fp_out);
220   fclose(fp_in);
221   }
222   }
223   }
224 }
225 
main(void)226 int main(void) {
227   _MM_SET_FLUSH_ZERO_MODE(_MM_FLUSH_ZERO_ON);
228   TestDSP();
229   // TestGrainSize();
230 }
231