1 /*
2     MusicIO.cpp
3 
4     Copyright 2009-2011, Alan Calvert
5     Copyright 2014-2020, Will Godfrey & others
6 
7     This file is part of yoshimi, which is free software: you can
8     redistribute it and/or modify it under the terms of the GNU General
9     Public License as published by the Free Software Foundation, either
10     version 2 of the License, or (at your option) any later version.
11 
12     yoshimi is distributed in the hope that it will be useful,
13     but WITHOUT ANY WARRANTY; without even the implied warranty of
14     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15     GNU General Public License for more details.
16 
17     You should have received a copy of the GNU General Public License
18     along with yoshimi.  If not, see <http://www.gnu.org/licenses/>.
19 
20 */
21 
22 /*
23  * Uncomment the following define to emulate aftertouch
24  * To get the impression of channel aftertouch we change the
25  * event of the specified controller number.
26  * Change the value to suit your circumstances.
27  */
28 //#define AFTERTOUCH_EMULATE 94
29 
30 #include "Misc/Config.h"
31 #include "Misc/SynthEngine.h"
32 #include "Misc/FormatFuncs.h"
33 #include "MusicIO/MusicIO.h"
34 
35 using func::asString;
36 
37 
MusicIO(SynthEngine * _synth,BeatTracker * _beatTracker)38 MusicIO::MusicIO(SynthEngine *_synth, BeatTracker *_beatTracker) :
39     interleaved(NULL),
40     beatTracker(_beatTracker),
41     synth(_synth)
42 {
43     memset(zynLeft, 0, sizeof(float *) * (NUM_MIDI_PARTS + 1));
44     memset(zynRight, 0, sizeof(float *) * (NUM_MIDI_PARTS + 1));
45     LV2_engine = synth->getIsLV2Plugin();
46 }
47 
48 
~MusicIO()49 MusicIO::~MusicIO()
50 {
51     for (int npart = 0; npart < (NUM_MIDI_PARTS + 1); ++npart)
52     {
53         if (zynLeft[npart])
54         {
55             fftwf_free(zynLeft[npart]);
56             zynLeft[npart] = NULL;
57         }
58         if (zynRight[npart])
59         {
60             fftwf_free(zynRight[npart]);
61             zynRight[npart] = NULL;
62         }
63     }
64 }
65 
66 
setMidi(unsigned char par0,unsigned char par1,unsigned char par2,bool in_place)67 void MusicIO::setMidi(unsigned char par0, unsigned char par1, unsigned char par2, bool in_place)
68 {
69     if (synth->audioOut.load() != _SYS_::mute::Idle)
70         return; // nobody listening!
71 
72     bool inSync = LV2_engine || (synth->getRuntime().audioEngine == jack_audio && synth->getRuntime().midiEngine == jack_midi);
73 
74     CommandBlock putData;
75 
76     unsigned int event = par0 & 0xf0;
77     unsigned char channel = par0 & 0xf;
78 
79 
80 #ifdef AFTERTOUCH_EMULATE
81 
82     if (event == 0xb0 && par1 == AFTERTOUCH_EMULATE)
83     {
84         par0 = 0xd0 | channel; // change to chanel aftertouch
85         par1 = par2; // shift parameter across
86         synth->mididecode.midiProcess(par0, par1, par2, in_place, inSync);
87         return;
88     }
89 #endif
90 
91 /*
92  * This below is a much simpler (faster) way
93  * to do note-on and note-off
94  * Tested on ALSA JACK and LV2 all combinations!
95  */
96 
97     if (event == 0x80 || event == 0x90)
98     {
99         if (par2 < 1) // zero volume note on.
100             event = 0x80;
101 
102 #ifdef REPORT_NOTES_ON_OFF
103         if (event == 0x80) // note test
104             ++synth->getRuntime().noteOffSent;
105         else
106             ++synth->getRuntime().noteOnSent;
107 #endif
108 
109         if (inSync)
110         {
111             if (event == 0x80)
112                 synth->NoteOff(channel, par1);
113             else
114                 synth->NoteOn(channel, par1, par2);
115         }
116         else
117         {
118             putData.data.value = float(par2);
119             putData.data.type = 8;
120             putData.data.control = (event == 0x80);
121             putData.data.part = TOPLEVEL::section::midiIn;
122             putData.data.kit = channel;
123             putData.data.engine = par1;
124             synth->midilearn.writeMidi(&putData, false);
125         }
126         return;
127     }
128     synth->mididecode.midiProcess(par0, par1, par2, in_place, inSync);
129 }
130 
131 
prepBuffers(void)132 bool MusicIO::prepBuffers(void)
133 {
134     int buffersize = getBuffersize();
135     if (buffersize > 0)
136     {
137         for (int part = 0; part < (NUM_MIDI_PARTS + 1); part++)
138         {
139             if (!(zynLeft[part] = (float*) fftwf_malloc(buffersize * sizeof(float))))
140                 goto bail_out;
141             if (!(zynRight[part] = (float*) fftwf_malloc(buffersize * sizeof(float))))
142                 goto bail_out;
143             memset(zynLeft[part], 0, buffersize * sizeof(float));
144             memset(zynRight[part], 0, buffersize * sizeof(float));
145 
146         }
147         return true;
148     }
149 
150 bail_out:
151     synth->getRuntime().Log("Failed to allocate audio buffers, size " + asString(buffersize));
152     for (int part = 0; part < (NUM_MIDI_PARTS + 1); part++)
153     {
154         if (zynLeft[part])
155         {
156             fftwf_free(zynLeft[part]);
157             zynLeft[part] = NULL;
158         }
159         if (zynRight[part])
160         {
161             fftwf_free(zynRight[part]);
162             zynRight[part] = NULL;
163         }
164     }
165     if (interleaved)
166     {
167         delete[] interleaved;
168         interleaved = NULL;
169     }
170     return false;
171 }
172 
BeatTracker()173 BeatTracker::BeatTracker() :
174     songVsMonotonicBeatDiff(0)
175 {
176 }
177 
~BeatTracker()178 BeatTracker::~BeatTracker()
179 {
180 }
181 
adjustMonotonicRounding(BeatTracker::BeatValues * beats)182 void BeatTracker::adjustMonotonicRounding(BeatTracker::BeatValues *beats)
183 {
184     // Try to compensate for rounding errors in monotonic beat. If the
185     // difference is small enough from the song beat, then we assume we have not
186     // repositioned the transport and we derive an exact value of the monotonic
187     // beat from the song beat, instead of adding BPM on every cycle, which
188     // accumulates a lot of error over time.
189     if (fabsf(beats->songBeat + songVsMonotonicBeatDiff - beats->monotonicBeat) < 0.1f)
190         beats->monotonicBeat = beats->songBeat + songVsMonotonicBeatDiff;
191     else
192         songVsMonotonicBeatDiff = beats->monotonicBeat - beats->songBeat;
193 }
194 
MultithreadedBeatTracker()195 MultithreadedBeatTracker::MultithreadedBeatTracker()
196 {
197     timespec time;
198     clock_gettime(CLOCK_MONOTONIC, &time);
199 
200     uint64_t clock = time.tv_sec * 1000000 + time.tv_nsec / 1000;
201 
202     lastTimeUs = clock;
203     lastSongBeat = 0;
204     lastMonotonicBeat = 0;
205     timeUs = clock;
206     songBeat = 0;
207     monotonicBeat = 0;
208     bpm = 120;
209     pthread_mutex_init(&mutex, NULL);
210 }
211 
~MultithreadedBeatTracker()212 MultithreadedBeatTracker::~MultithreadedBeatTracker()
213 {
214     pthread_mutex_destroy(&mutex);
215 }
216 
setBeatValues(BeatTracker::BeatValues beats)217 BeatTracker::BeatValues MultithreadedBeatTracker::setBeatValues(BeatTracker::BeatValues beats)
218 {
219     timespec time;
220     clock_gettime(CLOCK_MONOTONIC, &time);
221 
222     uint64_t clock = time.tv_sec * 1000000 + time.tv_nsec / 1000;
223 
224     adjustMonotonicRounding(&beats);
225 
226     //--------------------------------
227     pthread_mutex_lock(&mutex);
228 
229     lastTimeUs = timeUs;
230 
231     if (beats.songBeat >= LFO_BPM_LCM) {
232         beats.songBeat -= LFO_BPM_LCM;
233         lastSongBeat = songBeat - LFO_BPM_LCM;
234     } else
235         lastSongBeat = songBeat;
236 
237     if (beats.monotonicBeat >= LFO_BPM_LCM) {
238         beats.monotonicBeat -= LFO_BPM_LCM;
239         lastMonotonicBeat = monotonicBeat - LFO_BPM_LCM;
240     } else
241         lastMonotonicBeat = monotonicBeat;
242 
243     timeUs = clock;
244     songBeat = beats.songBeat;
245     monotonicBeat = beats.monotonicBeat;
246     bpm = beats.bpm;
247 
248     pthread_mutex_unlock(&mutex);
249     //--------------------------------
250 
251     return beats;
252 }
253 
getBeatValues()254 BeatTracker::BeatValues MultithreadedBeatTracker::getBeatValues()
255 {
256     timespec t;
257     clock_gettime(CLOCK_MONOTONIC, &t);
258 
259     uint64_t clock = t.tv_sec * 1000000 + t.tv_nsec / 1000;
260 
261     BeatTracker::BeatValues ret;
262 
263     pthread_mutex_lock(&mutex);
264     uint64_t lastTime = lastTimeUs;
265     float lastSongBeatTmp = lastSongBeat;
266     float lastMonotonicBeatTmp = lastMonotonicBeat;
267     uint64_t time = timeUs;
268     float songBeatTmp = songBeat;
269     float monotonicBeatTmp = monotonicBeat;
270     ret.bpm = bpm;
271     pthread_mutex_unlock(&mutex);
272 
273     if (time == lastTime) {
274         if (clock - time > 1000000) {
275             // If no MIDI clock messages have arrived for over a second, revert
276             // to a static 120 BPM. This is just a fallback to prevent
277             // oscillators from stalling completely.
278             ret.songBeat = songBeatTmp + (float)(clock - time) / 1000000.0f * 120.0f / 60.0f;
279             ret.monotonicBeat = monotonicBeatTmp + (float)(clock - time) / 1000000.0f * 120.0f / 60.0f;
280         }
281     } else {
282         // Based on beat and clock from MIDI thread, interpolate and find the
283         // beat for audio thread.
284         float ratio = (float)(clock - lastTime) / (time - lastTime);
285         ret.songBeat = ratio * (songBeatTmp - lastSongBeatTmp) + lastSongBeatTmp;
286         ret.monotonicBeat = ratio * (monotonicBeatTmp - lastMonotonicBeatTmp) + lastMonotonicBeatTmp;
287     }
288 
289     return ret;
290 }
291 
SinglethreadedBeatTracker()292 SinglethreadedBeatTracker::SinglethreadedBeatTracker()
293 {
294     beats.songBeat = 0;
295     beats.monotonicBeat = 0;
296     beats.bpm = 120;
297 }
298 
setBeatValues(BeatTracker::BeatValues beats)299 BeatTracker::BeatValues SinglethreadedBeatTracker::setBeatValues(BeatTracker::BeatValues beats)
300 {
301     if (beats.songBeat >= LFO_BPM_LCM)
302         beats.songBeat -= LFO_BPM_LCM;
303     if (beats.monotonicBeat >= LFO_BPM_LCM)
304         beats.monotonicBeat -= LFO_BPM_LCM;
305 
306     adjustMonotonicRounding(&beats);
307 
308     this->beats = beats;
309 
310     return beats;
311 }
312 
getBeatValues()313 BeatTracker::BeatValues SinglethreadedBeatTracker::getBeatValues()
314 {
315     return beats;
316 }
317