2 * Copyright (C) 2021 Alexander Schmidt
4 * This file is part of Seamulator.
6 * Seamulator is free software: you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation, either version 3 of the License, or
9 * (at your option) any later version.
11 * Seamulator is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with Seamulator. If not, see <http://www.gnu.org/licenses/>.
20 #include "synthesizer.h"
34 #include <Eigen/Dense>
36 #include "watersurface.h"
38 using namespace Eigen;
40 Synthesizer::Synthesizer(ConstWaterSurfacePtr surface) :
41 m_surface{std::move(surface)},
42 m_startTime{std::chrono::system_clock::now()},
43 m_lastRuntime{getRuntime()}
45 stk::Stk::setSampleRate( 48000.0 );
46 stk::Stk::showWarnings( true );
48 m_dac = std::make_unique<stk::RtWvOut>(2);
50 //m_sine1.setFrequency( 441.0 );
51 //m_sine2.setFrequency( 520.0 );
53 //m_sine1.noteOn(40.0, 1.0);
54 // m_sine2.noteOn(74.0, 1.0);
56 //for (int i = 0; i < 10; ++i) {
57 // m_dots.emplace_back( std::make_unique<Dot>(m_surface->at(i, 0), 440.0) );
62 const std::vector<double> frequencies = {939.85, 704.09, 469.92, 352.04, 279.42, 1054.94, 704.09, 527.47, 418.65, 313.64};
64 for (const auto& frequency : frequencies) {
65 const std::array<int, 2> pos =
66 { rand() % m_surface->size(), rand() % m_surface->size() };
67 m_posDots.emplace_back(
68 PosDot{pos, std::make_unique<Dot>(m_surface->at(pos[0], pos[1]), frequency)} );
71 // m_dots.emplace_back( std::make_unique<Dot>(m_surface->at(10, 50), 939.85) );
72 // m_dots.emplace_back( std::make_unique<Dot>(m_surface->at(20, 40), 704.09) );
73 // m_dots.emplace_back( std::make_unique<Dot>(m_surface->at(30, 30), 469.92) );
74 // m_dots.emplace_back( std::make_unique<Dot>(m_surface->at(40, 20), 352.04) );
75 // m_dots.emplace_back( std::make_unique<Dot>(m_surface->at(50, 10), 279.42) );
77 // m_dots.emplace_back( std::make_unique<Dot>(m_surface->at(50, 10), 1054.94) );
78 // m_dots.emplace_back( std::make_unique<Dot>(m_surface->at(40, 20), 704.09) );
79 // m_dots.emplace_back( std::make_unique<Dot>(m_surface->at(30, 30), 527.47) );
80 // m_dots.emplace_back( std::make_unique<Dot>(m_surface->at(20, 40), 418.65) );
81 // m_dots.emplace_back( std::make_unique<Dot>(m_surface->at(10, 50), 313.64) );
83 m_audioThread = std::thread( [this]{audioLoop();} );
85 // std::cout << "NoteOn 0.0 1 64.000000 64.0" << std::endl;
86 // std::cout << std::flush;
88 // Figure out how many bytes in an StkFloat and setup the RtAudio stream.
89 // RtAudio::StreamParameters parameters;
90 // parameters.deviceId = m_dac.getDefaultOutputDevice();
91 // parameters.nChannels = 1;
92 // RtAudioFormat format = ( sizeof(stk::StkFloat) == 8 ) ? RTAUDIO_FLOAT64 : RTAUDIO_FLOAT32;
93 // unsigned int bufferFrames = stk::RT_BUFFER_SIZE;
95 // // auto aTick = std::bind(&Synthesizer::audioTick, this, _1, _2, _3, _4, _5, _6);
96 // std::function<int (void*, void*, unsigned int, double, unsigned int, void*)> bla = [this](void *outputBuffer, void *inputBuffer, unsigned int nBufferFrames,
97 // double streamTime, RtAudioStreamStatus status, void *dataPointer) -> int {
100 // m_dac.openStream( ¶meters, NULL, format, (unsigned int)stk::Stk::sampleRate(), &bufferFrames, bla,
101 // (void *)&m_sine );
103 // catch ( RtAudioError &error ) {
104 // // error.printMessage();
109 // m_sine.setFrequency(440.0);
111 // m_dac.startStream();
113 // catch ( RtAudioError &error ) {
114 // // error.printMessage();
120 Synthesizer::~Synthesizer()
123 m_audioThread.join();
126 void Synthesizer::tick()
128 const auto runtime = getRuntime();
129 const auto deltaT = runtime - m_lastRuntime;
131 for (auto& posDot : m_posDots) {
132 posDot.dot->advance(deltaT);
135 // const auto posBefore = m_pos;
136 // const auto posBefore2 = m_pos2;
138 // m_vel += -1.0 * ( m_pos - m_surface->at(0, 0).getHeight() ) * deltaT - deltaT * m_vel * 0.1;
139 // m_pos += m_vel * deltaT;
141 // //std::cout << m_vel << std::endl;
143 // std::cout << m_pos2 << std::endl;
145 // m_vel2 += -10.0 * ( m_pos2 - m_surface->at(10, 10).getHeight() ) * deltaT - deltaT * m_vel2 * 0.1;
146 // m_pos2 += m_vel2 * deltaT;
148 // m_velMax1 = std::max(m_velMax1, m_vel);
149 // m_velMax2 = std::max(m_velMax2, m_vel2);
151 // if (posBefore * m_pos < 0.0) {
152 // // std::cout << "ControlChange 0.0 2 7 " << 100 * std::fabs(m_vel) << std::endl;
154 // // std::cout << "NoteOn 0.0 2 75 64" << std::endl;
155 // // std::cout << std::flush;
156 // m_sine1.noteOn(m_pos >= 0 ? 440.0 : 329.628, m_vel / m_velMax1);
159 // if (posBefore2 * m_pos2 < 0.0) {
160 // // std::cout << "ControlChange 0.0 1 7 " << 100 * std::fabs(m_vel) << std::endl;
161 // // std::cout << "NoteOn 0.0 1 44 64" << std::endl;
162 // // std::cout << "NoteOff 0.1 1 44 64" << std::endl;
163 // // std::cout << std::flush;
164 // m_sine2.noteOn(m_pos2 >= 0 ? 440.0 : 329.628, m_vel2 / m_velMax2);
167 // // std::cout << std::fabs(m_vel) * 10000 << std::endl;
169 // // m_sine1.controlChange(128, std::fabs(m_vel) * 10000);
171 // // std::cout << "ControlChange 0.0 1 7 " << 100 * std::fabs(m_vel) << std::endl;
172 // // std::cout << "PitchChange 0.0 1 " << 42 + 0.1*m_pos << std::endl;
174 // // std::cout << "ControlChange 0.0 1 7 " << 64 + 100 * m_vel << std::endl;
175 // //std::cout << "AfterTouch 0.0 1 " << 64 + 10 * m_vel << std::endl;
176 // //std::cout << "PitchChange 0.0 1 " << 64 + 10*m_vel << std::endl;
178 // std::cout << std::flush;
182 m_lastRuntime = runtime;
185 void Synthesizer::audioLoop()
187 stk::PRCRev effect0(0.5);
189 stk::Echo echo2{4000};
190 stk::Echo echo3{7000};
191 stk::Chorus chorus{6000};
192 stk::StkFrames frames(88200, 2);
195 const Vector2d leftPos{0.0, -1.0};
196 const Vector2d rightPos{1.0, -1.0};
198 std::vector<double> dotDist;
200 for (std::size_t dotIdx = 0; dotIdx < m_posDots.size(); ++dotIdx) {
201 auto& posDot = m_posDots[dotIdx];
202 const Vector2d pos( static_cast<double>(posDot.pos[0]) / m_surface->size(),
203 static_cast<double>(posDot.pos[1]) / m_surface->size() );
204 dotDist.emplace_back( (leftPos - pos).squaredNorm() );
205 dotDist.emplace_back( (rightPos - pos).squaredNorm() );
209 for (int i = 0; i < 88200; i++) {
212 for (std::size_t dotIdx = 0; dotIdx < m_posDots.size(); ++dotIdx) {
213 const auto tick = m_posDots[dotIdx].dot->tick();
214 frames(i, 0) += tick / dotDist[dotIdx*2];
215 frames(i, 1) += tick / dotDist[dotIdx*2+1];
216 // frames(i, 1) += (1.0 - normPosX) * tick;
218 //frames(i,1) = frames(i,0);
220 // frames = effect0.tick(frames);
221 frames = echo1.tick(frames);
222 // frames = echo2.tick(frames);
223 // frames = echo3.tick(frames);
225 frames = chorus.tick(frames);
231 double Synthesizer::getRuntime() const
233 auto timeNow = std::chrono::system_clock::now();
235 std::chrono::duration_cast<std::chrono::milliseconds>(timeNow - m_startTime);
236 return durationMs.count() / 1000.0;