]> git.treefish.org Git - seamulator.git/blob - src/synthesizer.cpp
place plucks at random positions
[seamulator.git] / src / synthesizer.cpp
1 /**
2  * Copyright (C) 2021  Alexander Schmidt
3  *
4  * This file is part of Seamulator.
5  *
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.
10  *
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.
15  *
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/>.
18  */
19
20 #include "synthesizer.h"
21
22 #include <cmath>
23 #include <functional>
24 #include <iostream>
25
26 #include <Stk.h>
27 #include <Echo.h>
28 #include <Chorus.h>
29 #include <FreeVerb.h>
30 #include <PitShift.h>
31 #include <PRCRev.h>
32 #include <NRev.h>
33
34 #include "watersurface.h"
35
36 using namespace std::placeholders;
37
38 Synthesizer::Synthesizer(ConstWaterSurfacePtr surface) :
39     m_surface{std::move(surface)},
40     m_startTime{std::chrono::system_clock::now()},
41     m_lastRuntime{getRuntime()}
42 {
43     stk::Stk::setSampleRate( 44100.0 );
44     stk::Stk::showWarnings( true );
45
46     m_dac = std::make_unique<stk::RtWvOut>(2);
47
48     //m_sine1.setFrequency( 441.0 );
49     //m_sine2.setFrequency( 520.0 );
50
51     //m_sine1.noteOn(40.0, 1.0);
52     // m_sine2.noteOn(74.0, 1.0);
53
54     //for (int i = 0; i < 10; ++i) {
55 //        m_dots.emplace_back( std::make_unique<Dot>(m_surface->at(i, 0), 440.0) );
56         //}
57
58     srand (time(NULL));
59     
60     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};
61
62     for (const auto& frequency : frequencies) {
63         m_dots.emplace_back( std::make_unique<Dot>(m_surface->at(rand() % m_surface->size(), rand() %  m_surface->size()), frequency) );
64     }
65     
66     // m_dots.emplace_back( std::make_unique<Dot>(m_surface->at(10, 50), 939.85) );
67     // m_dots.emplace_back( std::make_unique<Dot>(m_surface->at(20, 40), 704.09) );
68     // m_dots.emplace_back( std::make_unique<Dot>(m_surface->at(30, 30), 469.92) );
69     // m_dots.emplace_back( std::make_unique<Dot>(m_surface->at(40, 20), 352.04) );
70     // m_dots.emplace_back( std::make_unique<Dot>(m_surface->at(50, 10), 279.42) );
71
72     // m_dots.emplace_back( std::make_unique<Dot>(m_surface->at(50, 10), 1054.94) );
73     // m_dots.emplace_back( std::make_unique<Dot>(m_surface->at(40, 20), 704.09) );
74     // m_dots.emplace_back( std::make_unique<Dot>(m_surface->at(30, 30), 527.47) );
75     // m_dots.emplace_back( std::make_unique<Dot>(m_surface->at(20, 40), 418.65) );
76     // m_dots.emplace_back( std::make_unique<Dot>(m_surface->at(10, 50), 313.64) );
77
78     m_audioThread = std::thread( [this]{audioLoop();} );
79
80     // std::cout << "NoteOn 0.0 1 64.000000 64.0" << std::endl;
81     // std::cout << std::flush;
82
83     // Figure out how many bytes in an StkFloat and setup the RtAudio stream.
84 //     RtAudio::StreamParameters parameters;
85 //     parameters.deviceId = m_dac.getDefaultOutputDevice();
86 //     parameters.nChannels = 1;
87 //     RtAudioFormat format = ( sizeof(stk::StkFloat) == 8 ) ? RTAUDIO_FLOAT64 : RTAUDIO_FLOAT32;
88 //     unsigned int bufferFrames = stk::RT_BUFFER_SIZE;
89 //     try {
90 // //        auto aTick = std::bind(&Synthesizer::audioTick, this, _1, _2, _3, _4, _5, _6);
91 //         std::function<int (void*, void*, unsigned int, double, unsigned int, void*)> bla = [this](void *outputBuffer, void *inputBuffer, unsigned int nBufferFrames,
92 //                                                                                                              double streamTime, RtAudioStreamStatus status, void *dataPointer) -> int {
93 //             return 0;
94 //         };
95 //         m_dac.openStream( &parameters, NULL, format, (unsigned int)stk::Stk::sampleRate(), &bufferFrames, bla,
96 //                           (void *)&m_sine );
97 //     }
98 //     catch ( RtAudioError &error ) {
99 //         // error.printMessage();
100 //         // goto cleanup;
101 //         throw;
102 //     }
103
104 //     m_sine.setFrequency(440.0);
105 //     try {
106 //         m_dac.startStream();
107 //     }
108 //     catch ( RtAudioError &error ) {
109 //         // error.printMessage();
110 //         // goto cleanup;
111 //         throw;
112 //     }
113 }
114
115 Synthesizer::~Synthesizer()
116 {
117     m_stop = true;
118     m_audioThread.join();
119 }
120
121 void Synthesizer::tick()
122 {
123     const auto runtime = getRuntime();
124     const auto deltaT = runtime - m_lastRuntime;
125
126     for (auto& dot : m_dots) {
127         dot->advance(deltaT);
128     }
129     
130 //     const auto posBefore = m_pos;
131 //     const auto posBefore2 = m_pos2;
132
133 //     m_vel += -1.0 * ( m_pos - m_surface->at(0, 0).getHeight() ) * deltaT - deltaT * m_vel * 0.1;
134 //     m_pos += m_vel * deltaT;
135
136 //     //std::cout << m_vel << std::endl;
137
138 //     std::cout << m_pos2 << std::endl;
139
140 //     m_vel2 += -10.0 * ( m_pos2 - m_surface->at(10, 10).getHeight() ) * deltaT - deltaT * m_vel2 * 0.1;
141 //     m_pos2 += m_vel2 * deltaT;
142
143 //     m_velMax1 = std::max(m_velMax1, m_vel);
144 //     m_velMax2 = std::max(m_velMax2, m_vel2);
145     
146 //     if (posBefore * m_pos < 0.0) {
147 //         //      std::cout << "ControlChange 0.0 2 7 " << 100 * std::fabs(m_vel) << std::endl;
148 //         //m_sine1.noteOn(
149 //         // std::cout << "NoteOn 0.0 2 75 64" << std::endl;
150 //         // std::cout << std::flush;
151 //         m_sine1.noteOn(m_pos >= 0 ? 440.0 : 329.628, m_vel / m_velMax1);
152 //     }
153
154 //     if (posBefore2 * m_pos2 < 0.0) {
155 // //        std::cout << "ControlChange 0.0 1 7 " << 100 * std::fabs(m_vel) << std::endl;
156 //         // std::cout << "NoteOn 0.0 1 44 64" << std::endl;
157 // //        std::cout << "NoteOff 0.1 1 44 64" << std::endl;
158 //         // std::cout << std::flush;
159 //         m_sine2.noteOn(m_pos2 >= 0 ? 440.0 : 329.628, m_vel2 / m_velMax2);
160 //     }
161
162 //     // std::cout << std::fabs(m_vel) * 10000 << std::endl;
163
164 //     // m_sine1.controlChange(128, std::fabs(m_vel) * 10000);
165     
166 //     // std::cout << "ControlChange 0.0 1 7 " << 100 * std::fabs(m_vel) << std::endl;
167 //     // std::cout << "PitchChange 0.0 1 " << 42 + 0.1*m_pos << std::endl;
168
169 // //     std::cout << "ControlChange 0.0 1 7 " << 64 + 100 * m_vel << std::endl;
170 //     //std::cout << "AfterTouch 0.0 1 " << 64 + 10 * m_vel << std::endl;
171 //     //std::cout << "PitchChange 0.0 1 " << 64 + 10*m_vel << std::endl;
172
173 //     std::cout << std::flush;
174
175     
176     
177     m_lastRuntime = runtime;
178 }
179
180 void Synthesizer::audioLoop()
181 {
182     stk::PRCRev effect0(0.5);
183     stk::Echo echo1;
184     stk::Echo echo2{4000};
185     stk::Echo echo3{7000};
186     stk::Chorus chorus{6000};
187     stk::StkFrames frames(88200, 2);
188     while (!m_stop) {
189         for (int i = 0; i < 88200; i++) {
190             frames(i, 0) *= 0;
191             frames(i, 1) *= 0;
192             for (std::size_t dotIdx = 0; dotIdx < m_dots.size(); ++dotIdx) {
193                 frames(i, dotIdx % 2 == 0 ? 1 : 0) += m_dots[dotIdx]->tick();
194             }
195             //frames(i,1) = frames(i,0);
196         }
197         //       frames = effect0.tick(frames);
198         frames = echo1.tick(frames);
199         // frames = echo2.tick(frames);
200         // frames = echo3.tick(frames);
201
202         frames = chorus.tick(frames);
203
204         m_dac->tick(frames);
205     }
206 }
207
208 double Synthesizer::getRuntime() const
209 {
210   auto timeNow = std::chrono::system_clock::now();
211   auto durationMs =
212     std::chrono::duration_cast<std::chrono::milliseconds>(timeNow - m_startTime);
213   return durationMs.count() / 1000.0;
214 }