Files

copied
Last update 6 years 3 months by Olivier Gillet
Filesringstest
..
makefile
rings_test.cc
rings_test.cc
// Copyright 2015 Olivier Gillet. // // Author: Olivier Gillet (ol.gillet@gmail.com) // // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // You should have received a copy of the GNU General Public License // along with this program. If not, see <http://www.gnu.org/licenses/>. #include <cmath> #include <cstdio> #include <cstring> #include <cstdlib> #include <xmmintrin.h> #include "rings/dsp/part.h" #include "rings/dsp/onset_detector.h" #include "rings/dsp/string_synth_part.h" #include "rings/dsp/string_synth_oscillator.h" #include "rings/dsp/string_synth_voice.h" #include "stmlib/test/wav_writer.h" #include "stmlib/dsp/units.h" #include "stmlib/utils/random.h" using namespace rings; using namespace stmlib; const uint32_t kSampleRate = 48000; const uint16_t kAudioBlockSize = 24; uint16_t reverb_buffer[65536]; void TestModal() { WavWriter wav_writer(2, ::kSampleRate, 20); wav_writer.Open("rings_modal.wav"); Part part; part.Init(reverb_buffer); Patch patch; patch.structure = 0.25f; patch.brightness = 0.3f; patch.damping = 0.95f; patch.position = 0.75f; float sequence[] = { 69.0f, 57.0f, 45.0f, 57.0f, 69.0f }; int sequence_counter = -1; float impulse = 1.0f; part.set_polyphony(4); part.set_model(RESONATOR_MODEL_MODAL); for (uint32_t i = 0; i < ::kSampleRate * 20; i += kAudioBlockSize) { uint16_t tri = (i * 1); tri = tri > 32767 ? 65535 - tri : tri; uint16_t tri2 = (i / 6); tri2 = tri2 > 32767 ? 65535 - tri2 : tri2; float in[kAudioBlockSize]; float out[kAudioBlockSize]; float aux[kAudioBlockSize]; PerformanceState performance; performance.strum = false; if (i % (::kSampleRate * 2) == 0) { sequence_counter = (sequence_counter + 1) % 5; impulse = 1.0f; performance.strum = true; } for (size_t j = 0; j < kAudioBlockSize; ++j) { in[j] = impulse; impulse = impulse * 0.99f; } performance.note = sequence[sequence_counter] - 12.0f; performance.tonic = 0.0f; performance.fm = tri / 32768.0f; performance.internal_exciter = false; part.Process(performance, patch, in, out, aux, kAudioBlockSize); wav_writer.Write(out, aux, kAudioBlockSize); } } void TestString() { WavWriter wav_writer(2, ::kSampleRate, 20); wav_writer.Open("rings_string.wav"); Part part; part.Init(reverb_buffer); Patch patch; //patch.structure = 0.8f; patch.brightness = 0.3f; patch.damping = 0.8f; patch.position = 0.08f; patch.structure = 0.25f; float sequence[] = { 69.0f, 57.0f, 45.0f, 57.0f, 69.0f }; int sequence_counter = -1; part.set_polyphony(3); part.set_model(RESONATOR_MODEL_STRING); for (uint32_t i = 0; i < ::kSampleRate * 20; i += kAudioBlockSize) { uint16_t tri = (i / 2); tri = tri > 32767 ? 65535 - tri : tri; uint16_t tri2 = (i / 6); tri2 = tri2 > 32767 ? 65535 - tri2 : tri2; float in[kAudioBlockSize]; float out[kAudioBlockSize]; float aux[kAudioBlockSize]; // patch.position = 0.75f * tri / 32768.0f + 0.125f; //patch.structure = 0.5f * tri2 / 32768.0f + 0.5f; //patch.structure = 0.05f; patch.position = 0.85f; PerformanceState performance; performance.strum = false; performance.internal_exciter = true; if (i % (::kSampleRate /4 ) == 0) { sequence_counter = (sequence_counter + 1) % 5; performance.strum = true; } performance.note = sequence[sequence_counter] - 45.0f; performance.tonic = 45.0f - 12.0f; performance.fm = tri / 32768.0f * 0.00f - 0.0f + 0.0f * Random::GetFloat(); part.Process(performance, patch, in, out, aux, kAudioBlockSize); wav_writer.Write(out, aux, kAudioBlockSize); } } void TestFM() { FILE* fp_in = fopen("audio_samples/funk_kit.wav", "rb"); fseek(fp_in, 48, SEEK_SET); WavWriter wav_writer(2, ::kSampleRate, 20); wav_writer.Open("rings_fm.wav"); Part part; part.Init(reverb_buffer); Patch patch; patch.brightness = 0.9f; patch.damping = 0.5f; patch.position = 0.5f; patch.structure = 0.5f; float sequence[] = { 69.0f, 57.0f, 45.0f, 57.0f, 69.0f }; int sequence_counter = -1; part.set_polyphony(1); part.set_model(RESONATOR_MODEL_FM_VOICE); typedef struct { short l; short r; } ShortFrame; for (uint32_t i = 0; i < ::kSampleRate * 20; i += kAudioBlockSize) { ShortFrame input_frame[kAudioBlockSize]; bool no_input = true || fread( input_frame, sizeof(ShortFrame), kAudioBlockSize, fp_in) != kAudioBlockSize; uint16_t tri = (i / 2); tri = tri > 32767 ? 65535 - tri : tri; uint16_t tri2 = (i / 6); tri2 = tri2 > 32767 ? 65535 - tri2 : tri2; float in[kAudioBlockSize]; float out[kAudioBlockSize]; float aux[kAudioBlockSize]; // patch.brightness = tri / 32768.0f; //patch.position = tri / 32768.0f; PerformanceState performance; performance.strum = false; performance.internal_exciter = true; if (i % (::kSampleRate / 2) == 0) { sequence_counter = (sequence_counter + 1) % 6; performance.strum = true; } performance.note = /*sequence[sequence_counter] - 45.0f*/ - 3.0f - 12.0f * (sequence_counter & 1); performance.tonic = 45.0f; performance.fm = tri / 32768.0f * 0.00f - 0.0f + 0.0f * Random::GetFloat(); for (size_t j = 0; j < kAudioBlockSize; ++j) { in[j] = no_input ? 0.0f : input_frame[j].l / 32768.0f; } part.Process(performance, patch, in, out, aux, kAudioBlockSize); wav_writer.Write(out, aux, kAudioBlockSize); } fclose(fp_in); } void TestLowDelay() { FILE* fp_in = fopen("audio_samples/funk_kit.wav", "rb"); fseek(fp_in, 48, SEEK_SET); WavWriter wav_writer(2, ::kSampleRate, 20); wav_writer.Open("rings_low_delay.wav"); Part part; part.Init(reverb_buffer); Patch patch; patch.brightness = 1.0f; patch.damping = 0.9f; patch.position = 0.5f; patch.structure = 0.5f; float sequence[] = { 69.0f, 57.0f, 45.0f, 57.0f, 69.0f }; int sequence_counter = -1; part.set_polyphony(1); part.set_model(RESONATOR_MODEL_STRING); typedef struct { short l; short r; } ShortFrame; for (uint32_t i = 0; i < ::kSampleRate * 20; i += kAudioBlockSize) { ShortFrame input_frame[kAudioBlockSize]; bool no_input = fread( input_frame, sizeof(ShortFrame), kAudioBlockSize, fp_in) != kAudioBlockSize; uint16_t tri = (i / 2); tri = tri > 32767 ? 65535 - tri : tri; uint16_t tri2 = (i / 6); tri2 = tri2 > 32767 ? 65535 - tri2 : tri2; float in[kAudioBlockSize]; float out[kAudioBlockSize]; float aux[kAudioBlockSize]; // patch.brightness = tri / 32768.0f; //patch.position = tri / 32768.0f; PerformanceState performance; performance.strum = false; performance.internal_exciter = false; performance.note = 0.0f; performance.tonic = 19.0f; performance.fm = -48.0f; for (size_t j = 0; j < kAudioBlockSize; ++j) { in[j] = no_input ? 0.0f : input_frame[j].l / 32768.0f; } part.Process(performance, patch, in, out, aux, kAudioBlockSize); wav_writer.Write(out, aux, kAudioBlockSize); } fclose(fp_in); } void TestPitchAccuracy() { for (int32_t octave = 0; octave < 8; ++octave) { int32_t note = octave * 12 + 9; char name[80]; sprintf(name, "rings_note_%d.wav", note); WavWriter wav_writer(1, ::kSampleRate, 5); wav_writer.Open(name); Part part; part.Init(reverb_buffer); Patch patch; patch.brightness = 0.95f; patch.damping = 0.85f; patch.position = 0.6f; patch.structure = 0.25f; part.set_polyphony(1); part.set_model(RESONATOR_MODEL_STRING); for (uint32_t i = 0; i < ::kSampleRate * 5; i += kAudioBlockSize) { float in[kAudioBlockSize]; float out[kAudioBlockSize]; float aux[kAudioBlockSize]; std::fill(&in[0], &in[kAudioBlockSize], 0.0f); PerformanceState performance; performance.strum = i == 0; performance.internal_exciter = true; performance.note = 0.0f; performance.tonic = note; performance.fm = 0.0f; part.Process(performance, patch, in, out, aux, kAudioBlockSize); wav_writer.Write(out, kAudioBlockSize); } } } void TestNoteFilter() { const size_t kControlRate = ::kSampleRate / kAudioBlockSize; NoteFilter note_filter; note_filter.Init(kControlRate, 0.001f, 0.010f, 0.050f, 0.004f); // The ADC range is 84.0 // The maximum ADC noise is 1/256.0 sample. size_t note_counter = 0; FILE* fp = fopen("rings_pitch_filter.txt", "w"); float note = 0.0f; for (size_t i = 0; i < kControlRate * 2; ++i) { float t = i / float(kControlRate); if (note_counter == 0) { note_counter = kControlRate >> 1; note = roundf(Random::GetFloat() * 84.0f) + 19.0f; } --note_counter; float adc_noise = Random::GetFloat() * 0.32f - 0.16f; float filtered_note = note_filter.Process(note + adc_noise, false); fprintf( fp, "%f\t%f\t%f\t%f\n", t, note + adc_noise, filtered_note, note_filter.stable_note()); } fclose(fp); // Plot results with: // import numpy // import pylab // // data = numpy.loadtxt('rings_pitch_filter.txt') // t = data[:, 0] // adc_pitch = data[:, 1] // pitch = data[:, 2] // stable_pitch = data[:, 3] // // pylab.plot(t, adc_pitch, 'r') // pylab.plot(t, pitch, 'b') // pylab.plot(t, stable_pitch, 'g') // pylab.show() } void TestOnsetDf() { FILE* fp = fopen("rings_onset_df.wav", "wb"); //FILE* fp_in = fopen("audio_samples/tapping_48k.wav", "rb"); FILE* fp_in = fopen("audio_samples/funk_kit.wav", "rb"); fseek(fp_in, 48, SEEK_SET); WavWriter wav_writer(2, ::kSampleRate, 20); wav_writer.Open("rings_onset_df.wav"); OnsetDetector detector; detector.Init( 8.0f / ::kSampleRate, 160.0f / ::kSampleRate, 1600.0f / ::kSampleRate, 2000.0f, 0.05f); typedef struct { short l; short r; } ShortFrame; float sawtooth = 0.0f; for (uint32_t i = 0; i < ::kSampleRate * 20; i += kAudioBlockSize) { ShortFrame input_frame[kAudioBlockSize]; bool no_input = fread( input_frame, sizeof(ShortFrame), kAudioBlockSize, fp_in) != kAudioBlockSize; float in[kAudioBlockSize]; float out[kAudioBlockSize]; for (size_t j = 0; j < kAudioBlockSize; ++j) { in[j] = no_input ? 0.0f : input_frame[j].l / 32768.0f; } // for (size_t j = 0; j < kAudioBlockSize; ++j) { // in[j] = 2.0f * sawtooth - 1.0f; // sawtooth += 220.0f / ::kSampleRate; // if (sawtooth >= 1.0f) sawtooth -= 1.0f; // } float onset_df = detector.Process(in, kAudioBlockSize); fill(&out[0], &out[kAudioBlockSize], onset_df); wav_writer.Write(in, out, kAudioBlockSize); } fclose(fp_in); } void TestGain() { uint32_t block_duration = ::kSampleRate * 5; WavWriter wav_writer(2, ::kSampleRate, 20); wav_writer.Open("rings_gain.wav"); Part part; part.Init(reverb_buffer); Patch patch; part.set_polyphony(1); for (uint32_t i = 0; i < block_duration * 4; i += kAudioBlockSize) { if (i % block_duration == 0) { part.set_model(ResonatorModel(i / block_duration)); } float in[kAudioBlockSize]; float out[kAudioBlockSize]; float aux[kAudioBlockSize]; patch.brightness = 0.5f; patch.position = 0.8f; patch.structure = 0.25f; patch.damping = 0.7f; PerformanceState performance; performance.strum = (i % (::kSampleRate / 2)) == 0; performance.internal_exciter = (i % block_duration) < (block_duration / 2); performance.note = 0.0f; performance.tonic = 48.0f; performance.fm = 0.0f; if (performance.internal_exciter) { fill(&in[0], &in[kAudioBlockSize], 0.0f); } else { for (size_t j = 0; j < kAudioBlockSize; ++j) { in[j] = (Random::GetFloat() * 2.0f - 1.0f) * 0.25f; } } part.Process(performance, patch, in, out, aux, kAudioBlockSize); wav_writer.Write(out, aux, kAudioBlockSize); } } void TestStringSynthOscillator() { WavWriter wav_writer(1, ::kSampleRate, 10); wav_writer.Open("rings_string_synth_oscillator.wav"); StringSynthOscillator osc; osc.Init(); while (!wav_writer.done()) { float out[kAudioBlockSize]; fill(&out[0], &out[kAudioBlockSize], 0.0f); osc.Render<OSCILLATOR_SHAPE_DARK_SQUARE, false>( 100.0f / 48000.00f, 0.5f, 0.5f, out, kAudioBlockSize); wav_writer.Write(out, kAudioBlockSize, 32767.0f); } } void TestStringSynthVoice() { WavWriter wav_writer(1, ::kSampleRate, 10); wav_writer.Open("rings_string_synth_voice.wav"); StringSynthVoice<3> voice; voice.Init(); float amplitudes[6] = { 0.2f, 0.2f, 0.2f, 0.2f, 0.2f, 0.2f }; while (!wav_writer.done()) { float out[kAudioBlockSize]; fill(&out[0], &out[kAudioBlockSize], 0.0f); float base_frequency = (100.0f / 48000.0f) * (wav_writer.triangle(1) >= 0.5f ? 1.0f : 1024.0f); voice.Render( base_frequency, amplitudes, 3, out, kAudioBlockSize); wav_writer.Write(out, kAudioBlockSize); } } void TestStringSynthPart() { WavWriter wav_writer(2, ::kSampleRate, 48); wav_writer.Open("rings_string_synth.wav"); StringSynthPart part; part.Init(reverb_buffer); Patch patch; patch.brightness = 0.3f; patch.position = 0.0f; patch.structure = 0.42f; float sequence[] = { 69.0f, 57.0f, 45.0f, 57.0f, 69.0f }; int sequence_counter = -1; part.set_polyphony(2); part.set_fx(FX_REVERB); for (uint32_t i = 0; i < ::kSampleRate * 48; i += kAudioBlockSize) { uint16_t tri = (i / 3); tri = tri > 32767 ? 65535 - tri : tri; uint16_t tri2 = (i / 11); tri2 = tri2 > 32767 ? 65535 - tri2 : tri2; float in[kAudioBlockSize]; float out[kAudioBlockSize]; float aux[kAudioBlockSize]; fill(&in[0], &in[kAudioBlockSize], 0.0f); PerformanceState performance; performance.strum = false; performance.internal_exciter = true; patch.brightness = tri2 / 32768.0f; //patch.damping = 0.6f + tri / 32768.0f * 0.2f; patch.damping = 0.8f; if (i % (::kSampleRate * 2) == 0 && i < ::kSampleRate * 40) { sequence_counter = (sequence_counter + 1) % 5; performance.strum = true; } performance.note = sequence[sequence_counter] - 45.0f; performance.tonic = 45.0f - 2.0f; performance.fm = tri2 / 32768.0f * 0.10f - 0.0f + 0.0f * Random::GetFloat(); part.Process(performance, patch, in, out, aux, kAudioBlockSize); wav_writer.Write(out, aux, kAudioBlockSize); } } int main(void) { _MM_SET_FLUSH_ZERO_MODE(_MM_FLUSH_ZERO_ON); TestNoteFilter(); TestModal(); TestString(); // TestFM(); // TestLowDelay(); TestPitchAccuracy(); // TestOnsetDf(); TestGain(); TestStringSynthOscillator(); TestStringSynthVoice(); TestStringSynthPart(); }
Report a bug