You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

573 lines
15KB

  1. // Copyright 2015 Olivier Gillet.
  2. //
  3. // Author: Olivier Gillet (ol.gillet@gmail.com)
  4. //
  5. // This program is free software: you can redistribute it and/or modify
  6. // it under the terms of the GNU General Public License as published by
  7. // the Free Software Foundation, either version 3 of the License, or
  8. // (at your option) any later version.
  9. // This program is distributed in the hope that it will be useful,
  10. // but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12. // GNU General Public License for more details.
  13. // You should have received a copy of the GNU General Public License
  14. // along with this program. If not, see <http://www.gnu.org/licenses/>.
  15. #include <cmath>
  16. #include <cstdio>
  17. #include <cstring>
  18. #include <cstdlib>
  19. #include <xmmintrin.h>
  20. #include "rings/dsp/part.h"
  21. #include "rings/dsp/onset_detector.h"
  22. #include "rings/dsp/string_synth_part.h"
  23. #include "rings/dsp/string_synth_oscillator.h"
  24. #include "rings/dsp/string_synth_voice.h"
  25. #include "stmlib/test/wav_writer.h"
  26. #include "stmlib/dsp/units.h"
  27. #include "stmlib/utils/random.h"
  28. using namespace rings;
  29. using namespace stmlib;
  30. const uint32_t kSampleRate = 48000;
  31. const uint16_t kAudioBlockSize = 24;
  32. uint16_t reverb_buffer[65536];
  33. void TestModal() {
  34. WavWriter wav_writer(2, ::kSampleRate, 20);
  35. wav_writer.Open("rings_modal.wav");
  36. Part part;
  37. part.Init(reverb_buffer);
  38. Patch patch;
  39. patch.structure = 0.25f;
  40. patch.brightness = 0.3f;
  41. patch.damping = 0.95f;
  42. patch.position = 0.75f;
  43. float sequence[] = { 69.0f, 57.0f, 45.0f, 57.0f, 69.0f };
  44. int sequence_counter = -1;
  45. float impulse = 1.0f;
  46. part.set_polyphony(4);
  47. part.set_model(RESONATOR_MODEL_MODAL);
  48. for (uint32_t i = 0; i < ::kSampleRate * 20; i += kAudioBlockSize) {
  49. uint16_t tri = (i * 1);
  50. tri = tri > 32767 ? 65535 - tri : tri;
  51. uint16_t tri2 = (i / 6);
  52. tri2 = tri2 > 32767 ? 65535 - tri2 : tri2;
  53. float in[kAudioBlockSize];
  54. float out[kAudioBlockSize];
  55. float aux[kAudioBlockSize];
  56. PerformanceState performance;
  57. performance.strum = false;
  58. if (i % (::kSampleRate * 2) == 0) {
  59. sequence_counter = (sequence_counter + 1) % 5;
  60. impulse = 1.0f;
  61. performance.strum = true;
  62. }
  63. for (size_t j = 0; j < kAudioBlockSize; ++j) {
  64. in[j] = impulse;
  65. impulse = impulse * 0.99f;
  66. }
  67. performance.note = sequence[sequence_counter] - 12.0f;
  68. performance.tonic = 0.0f;
  69. performance.fm = tri / 32768.0f;
  70. performance.internal_exciter = false;
  71. part.Process(performance, patch, in, out, aux, kAudioBlockSize);
  72. wav_writer.Write(out, aux, kAudioBlockSize);
  73. }
  74. }
  75. void TestString() {
  76. WavWriter wav_writer(2, ::kSampleRate, 20);
  77. wav_writer.Open("rings_string.wav");
  78. Part part;
  79. part.Init(reverb_buffer);
  80. Patch patch;
  81. //patch.structure = 0.8f;
  82. patch.brightness = 0.3f;
  83. patch.damping = 0.8f;
  84. patch.position = 0.08f;
  85. patch.structure = 0.25f;
  86. float sequence[] = { 69.0f, 57.0f, 45.0f, 57.0f, 69.0f };
  87. int sequence_counter = -1;
  88. part.set_polyphony(3);
  89. part.set_model(RESONATOR_MODEL_STRING);
  90. for (uint32_t i = 0; i < ::kSampleRate * 20; i += kAudioBlockSize) {
  91. uint16_t tri = (i / 2);
  92. tri = tri > 32767 ? 65535 - tri : tri;
  93. uint16_t tri2 = (i / 6);
  94. tri2 = tri2 > 32767 ? 65535 - tri2 : tri2;
  95. float in[kAudioBlockSize];
  96. float out[kAudioBlockSize];
  97. float aux[kAudioBlockSize];
  98. // patch.position = 0.75f * tri / 32768.0f + 0.125f;
  99. //patch.structure = 0.5f * tri2 / 32768.0f + 0.5f;
  100. //patch.structure = 0.05f;
  101. patch.position = 0.85f;
  102. PerformanceState performance;
  103. performance.strum = false;
  104. performance.internal_exciter = true;
  105. if (i % (::kSampleRate /4 ) == 0) {
  106. sequence_counter = (sequence_counter + 1) % 5;
  107. performance.strum = true;
  108. }
  109. performance.note = sequence[sequence_counter] - 45.0f;
  110. performance.tonic = 45.0f - 12.0f;
  111. performance.fm = tri / 32768.0f * 0.00f - 0.0f + 0.0f * Random::GetFloat();
  112. part.Process(performance, patch, in, out, aux, kAudioBlockSize);
  113. wav_writer.Write(out, aux, kAudioBlockSize);
  114. }
  115. }
  116. void TestFM() {
  117. FILE* fp_in = fopen("audio_samples/funk_kit.wav", "rb");
  118. fseek(fp_in, 48, SEEK_SET);
  119. WavWriter wav_writer(2, ::kSampleRate, 20);
  120. wav_writer.Open("rings_fm.wav");
  121. Part part;
  122. part.Init(reverb_buffer);
  123. Patch patch;
  124. patch.brightness = 0.9f;
  125. patch.damping = 0.5f;
  126. patch.position = 0.5f;
  127. patch.structure = 0.5f;
  128. float sequence[] = { 69.0f, 57.0f, 45.0f, 57.0f, 69.0f };
  129. int sequence_counter = -1;
  130. part.set_polyphony(1);
  131. part.set_model(RESONATOR_MODEL_FM_VOICE);
  132. typedef struct { short l; short r; } ShortFrame;
  133. for (uint32_t i = 0; i < ::kSampleRate * 20; i += kAudioBlockSize) {
  134. ShortFrame input_frame[kAudioBlockSize];
  135. bool no_input = true || fread(
  136. input_frame,
  137. sizeof(ShortFrame),
  138. kAudioBlockSize,
  139. fp_in) != kAudioBlockSize;
  140. uint16_t tri = (i / 2);
  141. tri = tri > 32767 ? 65535 - tri : tri;
  142. uint16_t tri2 = (i / 6);
  143. tri2 = tri2 > 32767 ? 65535 - tri2 : tri2;
  144. float in[kAudioBlockSize];
  145. float out[kAudioBlockSize];
  146. float aux[kAudioBlockSize];
  147. // patch.brightness = tri / 32768.0f;
  148. //patch.position = tri / 32768.0f;
  149. PerformanceState performance;
  150. performance.strum = false;
  151. performance.internal_exciter = true;
  152. if (i % (::kSampleRate / 2) == 0) {
  153. sequence_counter = (sequence_counter + 1) % 6;
  154. performance.strum = true;
  155. }
  156. performance.note = /*sequence[sequence_counter] - 45.0f*/ - 3.0f - 12.0f * (sequence_counter & 1);
  157. performance.tonic = 45.0f;
  158. performance.fm = tri / 32768.0f * 0.00f - 0.0f + 0.0f * Random::GetFloat();
  159. for (size_t j = 0; j < kAudioBlockSize; ++j) {
  160. in[j] = no_input ? 0.0f : input_frame[j].l / 32768.0f;
  161. }
  162. part.Process(performance, patch, in, out, aux, kAudioBlockSize);
  163. wav_writer.Write(out, aux, kAudioBlockSize);
  164. }
  165. fclose(fp_in);
  166. }
  167. void TestLowDelay() {
  168. FILE* fp_in = fopen("audio_samples/funk_kit.wav", "rb");
  169. fseek(fp_in, 48, SEEK_SET);
  170. WavWriter wav_writer(2, ::kSampleRate, 20);
  171. wav_writer.Open("rings_low_delay.wav");
  172. Part part;
  173. part.Init(reverb_buffer);
  174. Patch patch;
  175. patch.brightness = 1.0f;
  176. patch.damping = 0.9f;
  177. patch.position = 0.5f;
  178. patch.structure = 0.5f;
  179. float sequence[] = { 69.0f, 57.0f, 45.0f, 57.0f, 69.0f };
  180. int sequence_counter = -1;
  181. part.set_polyphony(1);
  182. part.set_model(RESONATOR_MODEL_STRING);
  183. typedef struct { short l; short r; } ShortFrame;
  184. for (uint32_t i = 0; i < ::kSampleRate * 20; i += kAudioBlockSize) {
  185. ShortFrame input_frame[kAudioBlockSize];
  186. bool no_input = fread(
  187. input_frame,
  188. sizeof(ShortFrame),
  189. kAudioBlockSize,
  190. fp_in) != kAudioBlockSize;
  191. uint16_t tri = (i / 2);
  192. tri = tri > 32767 ? 65535 - tri : tri;
  193. uint16_t tri2 = (i / 6);
  194. tri2 = tri2 > 32767 ? 65535 - tri2 : tri2;
  195. float in[kAudioBlockSize];
  196. float out[kAudioBlockSize];
  197. float aux[kAudioBlockSize];
  198. // patch.brightness = tri / 32768.0f;
  199. //patch.position = tri / 32768.0f;
  200. PerformanceState performance;
  201. performance.strum = false;
  202. performance.internal_exciter = false;
  203. performance.note = 0.0f;
  204. performance.tonic = 19.0f;
  205. performance.fm = -48.0f;
  206. for (size_t j = 0; j < kAudioBlockSize; ++j) {
  207. in[j] = no_input ? 0.0f : input_frame[j].l / 32768.0f;
  208. }
  209. part.Process(performance, patch, in, out, aux, kAudioBlockSize);
  210. wav_writer.Write(out, aux, kAudioBlockSize);
  211. }
  212. fclose(fp_in);
  213. }
  214. void TestPitchAccuracy() {
  215. for (int32_t octave = 0; octave < 8; ++octave) {
  216. int32_t note = octave * 12 + 9;
  217. char name[80];
  218. sprintf(name, "rings_note_%d.wav", note);
  219. WavWriter wav_writer(1, ::kSampleRate, 5);
  220. wav_writer.Open(name);
  221. Part part;
  222. part.Init(reverb_buffer);
  223. Patch patch;
  224. patch.brightness = 0.95f;
  225. patch.damping = 0.85f;
  226. patch.position = 0.6f;
  227. patch.structure = 0.25f;
  228. part.set_polyphony(1);
  229. part.set_model(RESONATOR_MODEL_STRING);
  230. for (uint32_t i = 0; i < ::kSampleRate * 5; i += kAudioBlockSize) {
  231. float in[kAudioBlockSize];
  232. float out[kAudioBlockSize];
  233. float aux[kAudioBlockSize];
  234. std::fill(&in[0], &in[kAudioBlockSize], 0.0f);
  235. PerformanceState performance;
  236. performance.strum = i == 0;
  237. performance.internal_exciter = true;
  238. performance.note = 0.0f;
  239. performance.tonic = note;
  240. performance.fm = 0.0f;
  241. part.Process(performance, patch, in, out, aux, kAudioBlockSize);
  242. wav_writer.Write(out, kAudioBlockSize);
  243. }
  244. }
  245. }
  246. void TestNoteFilter() {
  247. const size_t kControlRate = ::kSampleRate / kAudioBlockSize;
  248. NoteFilter note_filter;
  249. note_filter.Init(kControlRate, 0.001f, 0.010f, 0.050f, 0.004f);
  250. // The ADC range is 84.0
  251. // The maximum ADC noise is 1/256.0 sample.
  252. size_t note_counter = 0;
  253. FILE* fp = fopen("rings_pitch_filter.txt", "w");
  254. float note = 0.0f;
  255. for (size_t i = 0; i < kControlRate * 2; ++i) {
  256. float t = i / float(kControlRate);
  257. if (note_counter == 0) {
  258. note_counter = kControlRate >> 1;
  259. note = roundf(Random::GetFloat() * 84.0f) + 19.0f;
  260. }
  261. --note_counter;
  262. float adc_noise = Random::GetFloat() * 0.32f - 0.16f;
  263. float filtered_note = note_filter.Process(note + adc_noise, false);
  264. fprintf(
  265. fp,
  266. "%f\t%f\t%f\t%f\n",
  267. t,
  268. note + adc_noise,
  269. filtered_note,
  270. note_filter.stable_note());
  271. }
  272. fclose(fp);
  273. // Plot results with:
  274. // import numpy
  275. // import pylab
  276. //
  277. // data = numpy.loadtxt('rings_pitch_filter.txt')
  278. // t = data[:, 0]
  279. // adc_pitch = data[:, 1]
  280. // pitch = data[:, 2]
  281. // stable_pitch = data[:, 3]
  282. //
  283. // pylab.plot(t, adc_pitch, 'r')
  284. // pylab.plot(t, pitch, 'b')
  285. // pylab.plot(t, stable_pitch, 'g')
  286. // pylab.show()
  287. }
  288. void TestOnsetDf() {
  289. FILE* fp = fopen("rings_onset_df.wav", "wb");
  290. //FILE* fp_in = fopen("audio_samples/tapping_48k.wav", "rb");
  291. FILE* fp_in = fopen("audio_samples/funk_kit.wav", "rb");
  292. fseek(fp_in, 48, SEEK_SET);
  293. WavWriter wav_writer(2, ::kSampleRate, 20);
  294. wav_writer.Open("rings_onset_df.wav");
  295. OnsetDetector detector;
  296. detector.Init(
  297. 8.0f / ::kSampleRate,
  298. 160.0f / ::kSampleRate,
  299. 1600.0f / ::kSampleRate,
  300. 2000.0f,
  301. 0.05f);
  302. typedef struct { short l; short r; } ShortFrame;
  303. float sawtooth = 0.0f;
  304. for (uint32_t i = 0; i < ::kSampleRate * 20; i += kAudioBlockSize) {
  305. ShortFrame input_frame[kAudioBlockSize];
  306. bool no_input = fread(
  307. input_frame,
  308. sizeof(ShortFrame),
  309. kAudioBlockSize,
  310. fp_in) != kAudioBlockSize;
  311. float in[kAudioBlockSize];
  312. float out[kAudioBlockSize];
  313. for (size_t j = 0; j < kAudioBlockSize; ++j) {
  314. in[j] = no_input ? 0.0f : input_frame[j].l / 32768.0f;
  315. }
  316. // for (size_t j = 0; j < kAudioBlockSize; ++j) {
  317. // in[j] = 2.0f * sawtooth - 1.0f;
  318. // sawtooth += 220.0f / ::kSampleRate;
  319. // if (sawtooth >= 1.0f) sawtooth -= 1.0f;
  320. // }
  321. float onset_df = detector.Process(in, kAudioBlockSize);
  322. fill(&out[0], &out[kAudioBlockSize], onset_df);
  323. wav_writer.Write(in, out, kAudioBlockSize);
  324. }
  325. fclose(fp_in);
  326. }
  327. void TestGain() {
  328. uint32_t block_duration = ::kSampleRate * 5;
  329. WavWriter wav_writer(2, ::kSampleRate, 20);
  330. wav_writer.Open("rings_gain.wav");
  331. Part part;
  332. part.Init(reverb_buffer);
  333. Patch patch;
  334. part.set_polyphony(1);
  335. for (uint32_t i = 0; i < block_duration * 4; i += kAudioBlockSize) {
  336. if (i % block_duration == 0) {
  337. part.set_model(ResonatorModel(i / block_duration));
  338. }
  339. float in[kAudioBlockSize];
  340. float out[kAudioBlockSize];
  341. float aux[kAudioBlockSize];
  342. patch.brightness = 0.5f;
  343. patch.position = 0.8f;
  344. patch.structure = 0.25f;
  345. patch.damping = 0.7f;
  346. PerformanceState performance;
  347. performance.strum = (i % (::kSampleRate / 2)) == 0;
  348. performance.internal_exciter = (i % block_duration) < (block_duration / 2);
  349. performance.note = 0.0f;
  350. performance.tonic = 48.0f;
  351. performance.fm = 0.0f;
  352. if (performance.internal_exciter) {
  353. fill(&in[0], &in[kAudioBlockSize], 0.0f);
  354. } else {
  355. for (size_t j = 0; j < kAudioBlockSize; ++j) {
  356. in[j] = (Random::GetFloat() * 2.0f - 1.0f) * 0.25f;
  357. }
  358. }
  359. part.Process(performance, patch, in, out, aux, kAudioBlockSize);
  360. wav_writer.Write(out, aux, kAudioBlockSize);
  361. }
  362. }
  363. void TestStringSynthOscillator() {
  364. WavWriter wav_writer(1, ::kSampleRate, 10);
  365. wav_writer.Open("rings_string_synth_oscillator.wav");
  366. StringSynthOscillator osc;
  367. osc.Init();
  368. while (!wav_writer.done()) {
  369. float out[kAudioBlockSize];
  370. fill(&out[0], &out[kAudioBlockSize], 0.0f);
  371. osc.Render<OSCILLATOR_SHAPE_DARK_SQUARE, false>(
  372. 100.0f / 48000.00f, 0.5f, 0.5f, out, kAudioBlockSize);
  373. wav_writer.Write(out, kAudioBlockSize, 32767.0f);
  374. }
  375. }
  376. void TestStringSynthVoice() {
  377. WavWriter wav_writer(1, ::kSampleRate, 10);
  378. wav_writer.Open("rings_string_synth_voice.wav");
  379. StringSynthVoice<3> voice;
  380. voice.Init();
  381. float amplitudes[6] = { 0.2f, 0.2f, 0.2f, 0.2f, 0.2f, 0.2f };
  382. while (!wav_writer.done()) {
  383. float out[kAudioBlockSize];
  384. fill(&out[0], &out[kAudioBlockSize], 0.0f);
  385. float base_frequency = (100.0f / 48000.0f) * (wav_writer.triangle(1) >= 0.5f ? 1.0f : 1024.0f);
  386. voice.Render(
  387. base_frequency,
  388. amplitudes,
  389. 3,
  390. out,
  391. kAudioBlockSize);
  392. wav_writer.Write(out, kAudioBlockSize);
  393. }
  394. }
  395. void TestStringSynthPart() {
  396. WavWriter wav_writer(2, ::kSampleRate, 48);
  397. wav_writer.Open("rings_string_synth.wav");
  398. StringSynthPart part;
  399. part.Init(reverb_buffer);
  400. Patch patch;
  401. patch.brightness = 0.3f;
  402. patch.position = 0.0f;
  403. patch.structure = 0.42f;
  404. float sequence[] = { 69.0f, 57.0f, 45.0f, 57.0f, 69.0f };
  405. int sequence_counter = -1;
  406. part.set_polyphony(2);
  407. part.set_fx(FX_REVERB);
  408. for (uint32_t i = 0; i < ::kSampleRate * 48; i += kAudioBlockSize) {
  409. uint16_t tri = (i / 3);
  410. tri = tri > 32767 ? 65535 - tri : tri;
  411. uint16_t tri2 = (i / 11);
  412. tri2 = tri2 > 32767 ? 65535 - tri2 : tri2;
  413. float in[kAudioBlockSize];
  414. float out[kAudioBlockSize];
  415. float aux[kAudioBlockSize];
  416. fill(&in[0], &in[kAudioBlockSize], 0.0f);
  417. PerformanceState performance;
  418. performance.strum = false;
  419. performance.internal_exciter = true;
  420. patch.brightness = tri2 / 32768.0f;
  421. //patch.damping = 0.6f + tri / 32768.0f * 0.2f;
  422. patch.damping = 0.8f;
  423. if (i % (::kSampleRate * 2) == 0 && i < ::kSampleRate * 40) {
  424. sequence_counter = (sequence_counter + 1) % 5;
  425. performance.strum = true;
  426. }
  427. performance.note = sequence[sequence_counter] - 45.0f;
  428. performance.tonic = 45.0f - 2.0f;
  429. performance.fm = tri2 / 32768.0f * 0.10f - 0.0f + 0.0f * Random::GetFloat();
  430. part.Process(performance, patch, in, out, aux, kAudioBlockSize);
  431. wav_writer.Write(out, aux, kAudioBlockSize);
  432. }
  433. }
  434. int main(void) {
  435. _MM_SET_FLUSH_ZERO_MODE(_MM_FLUSH_ZERO_ON);
  436. TestNoteFilter();
  437. TestModal();
  438. TestString();
  439. // TestFM();
  440. // TestLowDelay();
  441. TestPitchAccuracy();
  442. // TestOnsetDf();
  443. TestGain();
  444. TestStringSynthOscillator();
  445. TestStringSynthVoice();
  446. TestStringSynthPart();
  447. }