X-Git-Url: http://git.treefish.org/~alex/seamulator.git/blobdiff_plain/e729e891d35b7405434f4fc5a7dadcc8f3b9e414..ba8f356e863ed4a418f93c155e64eecaea0819bf:/src/synthesizer.cpp diff --git a/src/synthesizer.cpp b/src/synthesizer.cpp new file mode 100644 index 0000000..b2254c0 --- /dev/null +++ b/src/synthesizer.cpp @@ -0,0 +1,201 @@ +/** + * Copyright (C) 2021 Alexander Schmidt + * + * This file is part of Seamulator. + * + * Seamulator 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. + * + * Seamulator 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 Seamulator. If not, see . + */ + +#include "synthesizer.h" + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include "watersurface.h" + +using namespace std::placeholders; + +Synthesizer::Synthesizer(ConstWaterSurfacePtr surface) : + m_surface{std::move(surface)}, + m_startTime{std::chrono::system_clock::now()}, + m_lastRuntime{getRuntime()} +{ + stk::Stk::setSampleRate( 44100.0 ); + stk::Stk::showWarnings( true ); + + m_dac = std::make_unique(2); + + //m_sine1.setFrequency( 441.0 ); + //m_sine2.setFrequency( 520.0 ); + + //m_sine1.noteOn(40.0, 1.0); + // m_sine2.noteOn(74.0, 1.0); + + //for (int i = 0; i < 10; ++i) { +// m_dots.emplace_back( std::make_unique(m_surface->at(i, 0), 440.0) ); + //} + + m_dots.emplace_back( std::make_unique(m_surface->at(0, 0), 939.85) ); + m_dots.emplace_back( std::make_unique(m_surface->at(0, 10), 704.09) ); + m_dots.emplace_back( std::make_unique(m_surface->at(0, 20), 469.92) ); + m_dots.emplace_back( std::make_unique(m_surface->at(0, 30), 352.04) ); + m_dots.emplace_back( std::make_unique(m_surface->at(0, 40), 279.42) ); + + m_dots.emplace_back( std::make_unique(m_surface->at(10, 10), 1054.94) ); + m_dots.emplace_back( std::make_unique(m_surface->at(20, 10), 704.09) ); + m_dots.emplace_back( std::make_unique(m_surface->at(30, 10), 527.47) ); + m_dots.emplace_back( std::make_unique(m_surface->at(40, 10), 418.65) ); + m_dots.emplace_back( std::make_unique(m_surface->at(50, 10), 313.64) ); + + m_audioThread = std::thread( [this]{audioLoop();} ); + + // std::cout << "NoteOn 0.0 1 64.000000 64.0" << std::endl; + // std::cout << std::flush; + + // Figure out how many bytes in an StkFloat and setup the RtAudio stream. +// RtAudio::StreamParameters parameters; +// parameters.deviceId = m_dac.getDefaultOutputDevice(); +// parameters.nChannels = 1; +// RtAudioFormat format = ( sizeof(stk::StkFloat) == 8 ) ? RTAUDIO_FLOAT64 : RTAUDIO_FLOAT32; +// unsigned int bufferFrames = stk::RT_BUFFER_SIZE; +// try { +// // auto aTick = std::bind(&Synthesizer::audioTick, this, _1, _2, _3, _4, _5, _6); +// std::function bla = [this](void *outputBuffer, void *inputBuffer, unsigned int nBufferFrames, +// double streamTime, RtAudioStreamStatus status, void *dataPointer) -> int { +// return 0; +// }; +// m_dac.openStream( ¶meters, NULL, format, (unsigned int)stk::Stk::sampleRate(), &bufferFrames, bla, +// (void *)&m_sine ); +// } +// catch ( RtAudioError &error ) { +// // error.printMessage(); +// // goto cleanup; +// throw; +// } + +// m_sine.setFrequency(440.0); +// try { +// m_dac.startStream(); +// } +// catch ( RtAudioError &error ) { +// // error.printMessage(); +// // goto cleanup; +// throw; +// } +} + +Synthesizer::~Synthesizer() +{ + m_stop = true; + m_audioThread.join(); +} + +void Synthesizer::tick() +{ + const auto runtime = getRuntime(); + const auto deltaT = runtime - m_lastRuntime; + + for (auto& dot : m_dots) { + dot->advance(deltaT); + } + +// const auto posBefore = m_pos; +// const auto posBefore2 = m_pos2; + +// m_vel += -1.0 * ( m_pos - m_surface->at(0, 0).getHeight() ) * deltaT - deltaT * m_vel * 0.1; +// m_pos += m_vel * deltaT; + +// //std::cout << m_vel << std::endl; + +// std::cout << m_pos2 << std::endl; + +// m_vel2 += -10.0 * ( m_pos2 - m_surface->at(10, 10).getHeight() ) * deltaT - deltaT * m_vel2 * 0.1; +// m_pos2 += m_vel2 * deltaT; + +// m_velMax1 = std::max(m_velMax1, m_vel); +// m_velMax2 = std::max(m_velMax2, m_vel2); + +// if (posBefore * m_pos < 0.0) { +// // std::cout << "ControlChange 0.0 2 7 " << 100 * std::fabs(m_vel) << std::endl; +// //m_sine1.noteOn( +// // std::cout << "NoteOn 0.0 2 75 64" << std::endl; +// // std::cout << std::flush; +// m_sine1.noteOn(m_pos >= 0 ? 440.0 : 329.628, m_vel / m_velMax1); +// } + +// if (posBefore2 * m_pos2 < 0.0) { +// // std::cout << "ControlChange 0.0 1 7 " << 100 * std::fabs(m_vel) << std::endl; +// // std::cout << "NoteOn 0.0 1 44 64" << std::endl; +// // std::cout << "NoteOff 0.1 1 44 64" << std::endl; +// // std::cout << std::flush; +// m_sine2.noteOn(m_pos2 >= 0 ? 440.0 : 329.628, m_vel2 / m_velMax2); +// } + +// // std::cout << std::fabs(m_vel) * 10000 << std::endl; + +// // m_sine1.controlChange(128, std::fabs(m_vel) * 10000); + +// // std::cout << "ControlChange 0.0 1 7 " << 100 * std::fabs(m_vel) << std::endl; +// // std::cout << "PitchChange 0.0 1 " << 42 + 0.1*m_pos << std::endl; + +// // std::cout << "ControlChange 0.0 1 7 " << 64 + 100 * m_vel << std::endl; +// //std::cout << "AfterTouch 0.0 1 " << 64 + 10 * m_vel << std::endl; +// //std::cout << "PitchChange 0.0 1 " << 64 + 10*m_vel << std::endl; + +// std::cout << std::flush; + + + + m_lastRuntime = runtime; +} + +void Synthesizer::audioLoop() +{ + stk::PRCRev effect0(0.5); + stk::Echo effect; + stk::Chorus chorus{6000}; + stk::StkFrames frames(88200, 2); + while (!m_stop) { + for (int i = 0; i < 88200; i++) { + frames(i, 0) *= 0; + frames(i, 1) *= 0; + for (std::size_t dotIdx = 0; dotIdx < m_dots.size(); ++dotIdx) { + frames(i, dotIdx % 2 == 0 ? 1 : 0) += m_dots[dotIdx]->tick(); + } + //frames(i,1) = frames(i,0); + } + // frames = effect0.tick(frames); +// frames = effect.tick(frames); + frames = chorus.tick(frames); + + m_dac->tick(frames); + } +} + +double Synthesizer::getRuntime() const +{ + auto timeNow = std::chrono::system_clock::now(); + auto durationMs = + std::chrono::duration_cast(timeNow - m_startTime); + return durationMs.count() / 1000.0; +}