1 /*
2 * libOPNMIDI is a free Software MIDI synthesizer library with OPN2 (YM2612) emulation
3 *
4 * MIDI parser and player (Original code from ADLMIDI): Copyright (c) 2010-2014 Joel Yliluoma <bisqwit@iki.fi>
5 * OPNMIDI Library and YM2612 support: Copyright (c) 2017-2020 Vitaly Novichkov <admin@wohlnet.ru>
6 *
7 * Library is based on the ADLMIDI, a MIDI player for Linux and Windows with OPL3 emulation:
8 * http://iki.fi/bisqwit/source/adlmidi.html
9 *
10 * This program is free software: you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License as published by
12 * the Free Software Foundation, either version 3 of the License, or
13 * any later version.
14 *
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU General Public License for more details.
19 *
20 * You should have received a copy of the GNU General Public License
21 * along with this program. If not, see <http://www.gnu.org/licenses/>.
22 */
23
24 #include "opnmidi_midiplay.hpp"
25 #include "opnmidi_opn2.hpp"
26 #include "opnmidi_private.hpp"
27 #include "chips/opn_chip_base.h"
28 #ifndef OPNMIDI_DISABLE_MIDI_SEQUENCER
29 #include "midi_sequencer.hpp"
30 #endif
31
32 /* Unify MIDI player casting and interface between ADLMIDI and OPNMIDI */
33 #define GET_MIDI_PLAYER(device) reinterpret_cast<OPNMIDIplay *>((device)->opn2_midiPlayer)
34 typedef OPNMIDIplay MidiPlayer;
35
36 static OPN2_Version opn2_version = {
37 OPNMIDI_VERSION_MAJOR,
38 OPNMIDI_VERSION_MINOR,
39 OPNMIDI_VERSION_PATCHLEVEL
40 };
41
42 static const OPNMIDI_AudioFormat opn2_DefaultAudioFormat =
43 {
44 OPNMIDI_SampleType_S16,
45 sizeof(int16_t),
46 2 * sizeof(int16_t),
47 };
48
49 /*---------------------------EXPORTS---------------------------*/
50
opn2_init(long sample_rate)51 OPNMIDI_EXPORT struct OPN2_MIDIPlayer *opn2_init(long sample_rate)
52 {
53 OPN2_MIDIPlayer *midi_device;
54 midi_device = (OPN2_MIDIPlayer *)malloc(sizeof(OPN2_MIDIPlayer));
55 if(!midi_device)
56 {
57 OPN2MIDI_ErrorString = "Can't initialize OPNMIDI: out of memory!";
58 return NULL;
59 }
60
61 OPNMIDIplay *player = new(std::nothrow) OPNMIDIplay(static_cast<unsigned long>(sample_rate));
62 if(!player)
63 {
64 free(midi_device);
65 OPN2MIDI_ErrorString = "Can't initialize OPNMIDI: out of memory!";
66 return NULL;
67 }
68 midi_device->opn2_midiPlayer = player;
69 return midi_device;
70 }
71
opn2_setDeviceIdentifier(OPN2_MIDIPlayer * device,unsigned id)72 OPNMIDI_EXPORT int opn2_setDeviceIdentifier(OPN2_MIDIPlayer *device, unsigned id)
73 {
74 if(!device || id > 0x0f)
75 return -1;
76 MidiPlayer *play = GET_MIDI_PLAYER(device);
77 assert(play);
78 play->setDeviceId(static_cast<uint8_t>(id));
79 return 0;
80 }
81
opn2_setNumChips(OPN2_MIDIPlayer * device,int numCards)82 OPNMIDI_EXPORT int opn2_setNumChips(OPN2_MIDIPlayer *device, int numCards)
83 {
84 if(device == NULL)
85 return -2;
86
87 MidiPlayer *play = GET_MIDI_PLAYER(device);
88 assert(play);
89 play->m_setup.numChips = static_cast<unsigned int>(numCards);
90 if(play->m_setup.numChips < 1 || play->m_setup.numChips > OPN_MAX_CHIPS)
91 {
92 play->setErrorString("number of chips may only be 1.." OPN_MAX_CHIPS_STR ".\n");
93 return -1;
94 }
95
96 Synth &synth = *play->m_synth;
97 if(!synth.setupLocked())
98 {
99 synth.m_numChips = play->m_setup.numChips;
100 play->partialReset();
101 }
102
103 return 0;
104 }
105
opn2_getNumChips(struct OPN2_MIDIPlayer * device)106 OPNMIDI_EXPORT int opn2_getNumChips(struct OPN2_MIDIPlayer *device)
107 {
108 if(device == NULL)
109 return -2;
110 MidiPlayer *play = GET_MIDI_PLAYER(device);
111 assert(play);
112 return (int)play->m_setup.numChips;
113 }
114
opn2_getNumChipsObtained(struct OPN2_MIDIPlayer * device)115 OPNMIDI_EXPORT int opn2_getNumChipsObtained(struct OPN2_MIDIPlayer *device)
116 {
117 if(device == NULL)
118 return -2;
119 MidiPlayer *play = GET_MIDI_PLAYER(device);
120 assert(play);
121 return (int)play->m_synth->m_numChips;
122 }
123
124
opn2_reserveBanks(OPN2_MIDIPlayer * device,unsigned banks)125 OPNMIDI_EXPORT int opn2_reserveBanks(OPN2_MIDIPlayer *device, unsigned banks)
126 {
127 if(!device)
128 return -1;
129 MidiPlayer *play = GET_MIDI_PLAYER(device);
130 assert(play);
131 Synth::BankMap &map = play->m_synth->m_insBanks;
132 map.reserve(banks);
133 return (int)map.capacity();
134 }
135
opn2_getBank(OPN2_MIDIPlayer * device,const OPN2_BankId * idp,int flags,OPN2_Bank * bank)136 OPNMIDI_EXPORT int opn2_getBank(OPN2_MIDIPlayer *device, const OPN2_BankId *idp, int flags, OPN2_Bank *bank)
137 {
138 if(!device || !idp || !bank)
139 return -1;
140
141 OPN2_BankId id = *idp;
142 if(id.lsb > 127 || id.msb > 127 || id.percussive > 1)
143 return -1;
144 size_t idnumber = ((id.msb << 8) | id.lsb | (id.percussive ? size_t(Synth::PercussionTag) : 0));
145
146 MidiPlayer *play = GET_MIDI_PLAYER(device);
147 assert(play);
148 Synth::BankMap &map = play->m_synth->m_insBanks;
149
150 Synth::BankMap::iterator it;
151 if(!(flags & OPNMIDI_Bank_Create))
152 {
153 it = map.find(idnumber);
154 if(it == map.end())
155 return -1;
156 }
157 else
158 {
159 std::pair<size_t, Synth::Bank> value;
160 value.first = idnumber;
161 memset(&value.second, 0, sizeof(value.second));
162 for (unsigned i = 0; i < 128; ++i)
163 value.second.ins[i].flags = OpnInstMeta::Flag_NoSound;
164
165 std::pair<Synth::BankMap::iterator, bool> ir;
166 if((flags & OPNMIDI_Bank_CreateRt) == OPNMIDI_Bank_CreateRt)
167 {
168 ir = map.insert(value, Synth::BankMap::do_not_expand_t());
169 if(ir.first == map.end())
170 return -1;
171 }
172 else
173 ir = map.insert(value);
174 it = ir.first;
175 }
176
177 it.to_ptrs(bank->pointer);
178 return 0;
179 }
180
opn2_getBankId(OPN2_MIDIPlayer * device,const OPN2_Bank * bank,OPN2_BankId * id)181 OPNMIDI_EXPORT int opn2_getBankId(OPN2_MIDIPlayer *device, const OPN2_Bank *bank, OPN2_BankId *id)
182 {
183 if(!device || !bank)
184 return -1;
185
186 Synth::BankMap::iterator it = Synth::BankMap::iterator::from_ptrs(bank->pointer);
187 Synth::BankMap::key_type idnumber = it->first;
188 id->msb = (idnumber >> 8) & 127;
189 id->lsb = idnumber & 127;
190 id->percussive = (idnumber & Synth::PercussionTag) ? 1 : 0;
191 return 0;
192 }
193
opn2_removeBank(OPN2_MIDIPlayer * device,OPN2_Bank * bank)194 OPNMIDI_EXPORT int opn2_removeBank(OPN2_MIDIPlayer *device, OPN2_Bank *bank)
195 {
196 if(!device || !bank)
197 return -1;
198
199 MidiPlayer *play = GET_MIDI_PLAYER(device);
200 assert(play);
201 Synth::BankMap &map = play->m_synth->m_insBanks;
202 Synth::BankMap::iterator it = Synth::BankMap::iterator::from_ptrs(bank->pointer);
203 size_t size = map.size();
204 map.erase(it);
205 return (map.size() != size) ? 0 : -1;
206 }
207
opn2_getFirstBank(OPN2_MIDIPlayer * device,OPN2_Bank * bank)208 OPNMIDI_EXPORT int opn2_getFirstBank(OPN2_MIDIPlayer *device, OPN2_Bank *bank)
209 {
210 if(!device)
211 return -1;
212
213 MidiPlayer *play = GET_MIDI_PLAYER(device);
214 assert(play);
215 Synth::BankMap &map = play->m_synth->m_insBanks;
216
217 Synth::BankMap::iterator it = map.begin();
218 if(it == map.end())
219 return -1;
220
221 it.to_ptrs(bank->pointer);
222 return 0;
223 }
224
opn2_getNextBank(OPN2_MIDIPlayer * device,OPN2_Bank * bank)225 OPNMIDI_EXPORT int opn2_getNextBank(OPN2_MIDIPlayer *device, OPN2_Bank *bank)
226 {
227 if(!device)
228 return -1;
229
230 MidiPlayer *play = GET_MIDI_PLAYER(device);
231 assert(play);
232 Synth::BankMap &map = play->m_synth->m_insBanks;
233
234 Synth::BankMap::iterator it = Synth::BankMap::iterator::from_ptrs(bank->pointer);
235 if(++it == map.end())
236 return -1;
237
238 it.to_ptrs(bank->pointer);
239 return 0;
240 }
241
opn2_getInstrument(OPN2_MIDIPlayer * device,const OPN2_Bank * bank,unsigned index,OPN2_Instrument * ins)242 OPNMIDI_EXPORT int opn2_getInstrument(OPN2_MIDIPlayer *device, const OPN2_Bank *bank, unsigned index, OPN2_Instrument *ins)
243 {
244 if(!device || !bank || index > 127 || !ins)
245 return -1;
246
247 Synth::BankMap::iterator it = Synth::BankMap::iterator::from_ptrs(bank->pointer);
248 cvt_FMIns_to_OPNI(*ins, it->second.ins[index]);
249 ins->version = 0;
250 return 0;
251 }
252
opn2_setInstrument(OPN2_MIDIPlayer * device,OPN2_Bank * bank,unsigned index,const OPN2_Instrument * ins)253 OPNMIDI_EXPORT int opn2_setInstrument(OPN2_MIDIPlayer *device, OPN2_Bank *bank, unsigned index, const OPN2_Instrument *ins)
254 {
255 if(!device || !bank || index > 127 || !ins)
256 return -1;
257
258 if(ins->version != 0)
259 return -1;
260
261 Synth::BankMap::iterator it = Synth::BankMap::iterator::from_ptrs(bank->pointer);
262 cvt_OPNI_to_FMIns(it->second.ins[index], *ins);
263 return 0;
264 }
265
opn2_openBankFile(OPN2_MIDIPlayer * device,const char * filePath)266 OPNMIDI_EXPORT int opn2_openBankFile(OPN2_MIDIPlayer *device, const char *filePath)
267 {
268 if(device)
269 {
270 MidiPlayer *play = GET_MIDI_PLAYER(device);
271 assert(play);
272 play->m_setup.tick_skip_samples_delay = 0;
273 if(!play->LoadBank(filePath))
274 {
275 std::string err = play->getErrorString();
276 if(err.empty())
277 play->setErrorString("OPN2 MIDI: Can't load file");
278 return -1;
279 }
280 else
281 return 0;
282 }
283 OPN2MIDI_ErrorString = "Can't load file: OPN2 MIDI is not initialized";
284 return -1;
285 }
286
opn2_openBankData(OPN2_MIDIPlayer * device,const void * mem,long size)287 OPNMIDI_EXPORT int opn2_openBankData(OPN2_MIDIPlayer *device, const void *mem, long size)
288 {
289 if(device)
290 {
291 MidiPlayer *play = GET_MIDI_PLAYER(device);
292 assert(play);
293 play->m_setup.tick_skip_samples_delay = 0;
294 if(!play->LoadBank(mem, static_cast<size_t>(size)))
295 {
296 std::string err = play->getErrorString();
297 if(err.empty())
298 play->setErrorString("OPN2 MIDI: Can't load data from memory");
299 return -1;
300 }
301 else return 0;
302 }
303
304 OPN2MIDI_ErrorString = "Can't load file: OPN2 MIDI is not initialized";
305 return -1;
306 }
307
opn2_setLfoEnabled(struct OPN2_MIDIPlayer * device,int lfoEnable)308 OPNMIDI_EXPORT void opn2_setLfoEnabled(struct OPN2_MIDIPlayer *device, int lfoEnable)
309 {
310 if(!device) return;
311 MidiPlayer *play = GET_MIDI_PLAYER(device);
312 assert(play);
313 Synth &synth = *play->m_synth;
314 play->m_setup.lfoEnable = lfoEnable;
315 synth.m_lfoEnable = (lfoEnable < 0 ?
316 synth.m_insBankSetup.lfoEnable :
317 play->m_setup.lfoEnable) != 0;
318 synth.commitLFOSetup();
319 }
320
opn2_getLfoEnabled(struct OPN2_MIDIPlayer * device)321 OPNMIDI_EXPORT int opn2_getLfoEnabled(struct OPN2_MIDIPlayer *device)
322 {
323 if(!device) return -1;
324 MidiPlayer *play = GET_MIDI_PLAYER(device);
325 assert(play);
326 return play->m_synth->m_lfoEnable;
327 }
328
opn2_setLfoFrequency(struct OPN2_MIDIPlayer * device,int lfoFrequency)329 OPNMIDI_EXPORT void opn2_setLfoFrequency(struct OPN2_MIDIPlayer *device, int lfoFrequency)
330 {
331 if(!device) return;
332 MidiPlayer *play = GET_MIDI_PLAYER(device);
333 assert(play);
334 Synth &synth = *play->m_synth;
335 play->m_setup.lfoFrequency = lfoFrequency;
336 synth.m_lfoFrequency = lfoFrequency < 0 ?
337 synth.m_insBankSetup.lfoFrequency :
338 (uint8_t)play->m_setup.lfoFrequency;
339 synth.commitLFOSetup();
340 }
341
opn2_getLfoFrequency(struct OPN2_MIDIPlayer * device)342 OPNMIDI_EXPORT int opn2_getLfoFrequency(struct OPN2_MIDIPlayer *device)
343 {
344 if(!device) return -1;
345 MidiPlayer *play = GET_MIDI_PLAYER(device);
346 assert(play);
347 return play->m_synth->m_lfoFrequency;
348 }
349
350 /*Override chip type. -1 - use bank default state*/
opn2_setChipType(struct OPN2_MIDIPlayer * device,int chipType)351 OPNMIDI_EXPORT void opn2_setChipType(struct OPN2_MIDIPlayer *device, int chipType)
352 {
353 if(!device) return;
354 MidiPlayer *play = GET_MIDI_PLAYER(device);
355 assert(play);
356 play->m_setup.chipType = chipType;
357 play->applySetup();
358 }
359
360 /*Get the chip type*/
opn2_getChipType(struct OPN2_MIDIPlayer * device)361 OPNMIDI_EXPORT int opn2_getChipType(struct OPN2_MIDIPlayer *device)
362 {
363 if(!device) return -1;
364 MidiPlayer *play = GET_MIDI_PLAYER(device);
365 assert(play);
366 return play->m_synth->chipFamily();
367 }
368
opn2_setScaleModulators(OPN2_MIDIPlayer * device,int smod)369 OPNMIDI_EXPORT void opn2_setScaleModulators(OPN2_MIDIPlayer *device, int smod)
370 {
371 if(!device)
372 return;
373 MidiPlayer *play = GET_MIDI_PLAYER(device);
374 assert(play);
375 play->m_setup.ScaleModulators = smod;
376 play->m_synth->m_scaleModulators = (play->m_setup.ScaleModulators != 0);
377 }
378
opn2_setFullRangeBrightness(struct OPN2_MIDIPlayer * device,int fr_brightness)379 OPNMIDI_EXPORT void opn2_setFullRangeBrightness(struct OPN2_MIDIPlayer *device, int fr_brightness)
380 {
381 if(!device)
382 return;
383 MidiPlayer *play = GET_MIDI_PLAYER(device);
384 assert(play);
385 play->m_setup.fullRangeBrightnessCC74 = (fr_brightness != 0);
386 }
387
opn2_setLoopEnabled(OPN2_MIDIPlayer * device,int loopEn)388 OPNMIDI_EXPORT void opn2_setLoopEnabled(OPN2_MIDIPlayer *device, int loopEn)
389 {
390 #ifndef OPNMIDI_DISABLE_MIDI_SEQUENCER
391 if(!device)
392 return;
393 MidiPlayer *play = GET_MIDI_PLAYER(device);
394 assert(play);
395 play->m_sequencer->setLoopEnabled(loopEn != 0);
396 #else
397 ADL_UNUSED(device);
398 ADL_UNUSED(loopEn);
399 #endif
400 }
401
opn2_setSoftPanEnabled(OPN2_MIDIPlayer * device,int softPanEn)402 OPNMIDI_EXPORT void opn2_setSoftPanEnabled(OPN2_MIDIPlayer *device, int softPanEn)
403 {
404 if(!device)
405 return;
406 MidiPlayer *play = GET_MIDI_PLAYER(device);
407 assert(play);
408 play->m_synth->m_softPanning = (softPanEn != 0);
409 }
410
411 /* !!!DEPRECATED!!! */
opn2_setLogarithmicVolumes(struct OPN2_MIDIPlayer * device,int logvol)412 OPNMIDI_EXPORT void opn2_setLogarithmicVolumes(struct OPN2_MIDIPlayer *device, int logvol)
413 {
414 if(!device)
415 return;
416 MidiPlayer *play = GET_MIDI_PLAYER(device);
417 assert(play);
418 Synth &synth = *play->m_synth;
419 play->m_setup.LogarithmicVolumes = static_cast<unsigned int>(logvol);
420 if(!synth.setupLocked())
421 {
422 if(play->m_setup.LogarithmicVolumes != 0)
423 synth.setVolumeScaleModel(OPNMIDI_VolumeModel_NativeOPN2);
424 else
425 synth.setVolumeScaleModel(static_cast<OPNMIDI_VolumeModels>(play->m_setup.VolumeModel));
426 }
427 }
428
opn2_setVolumeRangeModel(OPN2_MIDIPlayer * device,int volumeModel)429 OPNMIDI_EXPORT void opn2_setVolumeRangeModel(OPN2_MIDIPlayer *device, int volumeModel)
430 {
431 if(!device)
432 return;
433 MidiPlayer *play = GET_MIDI_PLAYER(device);
434 assert(play);
435 Synth &synth = *play->m_synth;
436 play->m_setup.VolumeModel = volumeModel;
437 if(!synth.setupLocked())
438 {
439 if(play->m_setup.VolumeModel == OPNMIDI_VolumeModel_AUTO)//Use bank default volume model
440 synth.m_volumeScale = (Synth::VolumesScale)synth.m_insBankSetup.volumeModel;
441 else
442 synth.setVolumeScaleModel(static_cast<OPNMIDI_VolumeModels>(volumeModel));
443 }
444 }
445
opn2_getVolumeRangeModel(struct OPN2_MIDIPlayer * device)446 OPNMIDI_EXPORT int opn2_getVolumeRangeModel(struct OPN2_MIDIPlayer *device)
447 {
448 if(!device)
449 return -1;
450 MidiPlayer *play = GET_MIDI_PLAYER(device);
451 assert(play);
452 return play->m_synth->getVolumeScaleModel();
453 }
454
opn2_openFile(OPN2_MIDIPlayer * device,const char * filePath)455 OPNMIDI_EXPORT int opn2_openFile(OPN2_MIDIPlayer *device, const char *filePath)
456 {
457 if(device)
458 {
459 MidiPlayer *play = GET_MIDI_PLAYER(device);
460 assert(play);
461 #ifndef OPNMIDI_DISABLE_MIDI_SEQUENCER
462 play->m_setup.tick_skip_samples_delay = 0;
463 if(!play->LoadMIDI(filePath))
464 {
465 std::string err = play->getErrorString();
466 if(err.empty())
467 play->setErrorString("OPN2 MIDI: Can't load file");
468 return -1;
469 }
470 else return 0;
471 #else
472 ADL_UNUSED(filePath);
473 play->setErrorString("OPNMIDI: MIDI Sequencer is not supported in this build of library!");
474 return -1;
475 #endif
476 }
477
478 OPN2MIDI_ErrorString = "Can't load file: OPN2 MIDI is not initialized";
479 return -1;
480 }
481
opn2_openData(OPN2_MIDIPlayer * device,const void * mem,unsigned long size)482 OPNMIDI_EXPORT int opn2_openData(OPN2_MIDIPlayer *device, const void *mem, unsigned long size)
483 {
484 if(device)
485 {
486 MidiPlayer *play = GET_MIDI_PLAYER(device);
487 assert(play);
488 #ifndef OPNMIDI_DISABLE_MIDI_SEQUENCER
489 play->m_setup.tick_skip_samples_delay = 0;
490 if(!play->LoadMIDI(mem, static_cast<size_t>(size)))
491 {
492 std::string err = play->getErrorString();
493 if(err.empty())
494 play->setErrorString("OPN2 MIDI: Can't load data from memory");
495 return -1;
496 }
497 else return 0;
498 #else
499 ADL_UNUSED(mem);
500 ADL_UNUSED(size);
501 play->setErrorString("OPNMIDI: MIDI Sequencer is not supported in this build of library!");
502 return -1;
503 #endif
504 }
505
506 OPN2MIDI_ErrorString = "Can't load file: OPN2 MIDI is not initialized";
507 return -1;
508 }
509
opn2_emulatorName()510 OPNMIDI_EXPORT const char *opn2_emulatorName()
511 {
512 return "<opn2_emulatorName() is deprecated! Use opn2_chipEmulatorName() instead!>";
513 }
514
opn2_chipEmulatorName(struct OPN2_MIDIPlayer * device)515 OPNMIDI_EXPORT const char *opn2_chipEmulatorName(struct OPN2_MIDIPlayer *device)
516 {
517 if(device)
518 {
519 MidiPlayer *play = GET_MIDI_PLAYER(device);
520 assert(play);
521 Synth &synth = *play->m_synth;
522 if(!synth.m_chips.empty())
523 return synth.m_chips[0]->emulatorName();
524 }
525 return "Unknown";
526 }
527
opn2_switchEmulator(struct OPN2_MIDIPlayer * device,int emulator)528 OPNMIDI_EXPORT int opn2_switchEmulator(struct OPN2_MIDIPlayer *device, int emulator)
529 {
530 if(device)
531 {
532 MidiPlayer *play = GET_MIDI_PLAYER(device);
533 assert(play);
534 if(opn2_isEmulatorAvailable(emulator))
535 {
536 play->m_setup.emulator = emulator;
537 play->partialReset();
538 return 0;
539 }
540 play->setErrorString("OPN2 MIDI: Unknown emulation core!");
541 }
542 return -1;
543 }
544
545
opn2_setRunAtPcmRate(OPN2_MIDIPlayer * device,int enabled)546 OPNMIDI_EXPORT int opn2_setRunAtPcmRate(OPN2_MIDIPlayer *device, int enabled)
547 {
548 if(device)
549 {
550 MidiPlayer *play = GET_MIDI_PLAYER(device);
551 assert(play);
552 Synth &synth = *play->m_synth;
553 play->m_setup.runAtPcmRate = (enabled != 0);
554 if(!synth.setupLocked())
555 play->partialReset();
556 return 0;
557 }
558 return -1;
559 }
560
561
opn2_linkedLibraryVersion()562 OPNMIDI_EXPORT const char *opn2_linkedLibraryVersion()
563 {
564 #if !defined(OPNMIDI_ENABLE_HQ_RESAMPLER)
565 return OPNMIDI_VERSION;
566 #else
567 return OPNMIDI_VERSION " (HQ)";
568 #endif
569 }
570
opn2_linkedVersion()571 OPNMIDI_EXPORT const OPN2_Version *opn2_linkedVersion()
572 {
573 return &opn2_version;
574 }
575
opn2_errorString()576 OPNMIDI_EXPORT const char *opn2_errorString()
577 {
578 return OPN2MIDI_ErrorString.c_str();
579 }
580
opn2_errorInfo(struct OPN2_MIDIPlayer * device)581 OPNMIDI_EXPORT const char *opn2_errorInfo(struct OPN2_MIDIPlayer *device)
582 {
583 if(!device)
584 return opn2_errorString();
585 MidiPlayer *play = GET_MIDI_PLAYER(device);
586 if(!play)
587 return opn2_errorString();
588 return play->getErrorString().c_str();
589 }
590
opn2_close(OPN2_MIDIPlayer * device)591 OPNMIDI_EXPORT void opn2_close(OPN2_MIDIPlayer *device)
592 {
593 if(!device)
594 return;
595 MidiPlayer *play = GET_MIDI_PLAYER(device);
596 assert(play);
597 delete play;
598 device->opn2_midiPlayer = NULL;
599 free(device);
600 device = NULL;
601 }
602
opn2_reset(OPN2_MIDIPlayer * device)603 OPNMIDI_EXPORT void opn2_reset(OPN2_MIDIPlayer *device)
604 {
605 if(!device)
606 return;
607 MidiPlayer *play = GET_MIDI_PLAYER(device);
608 assert(play);
609 play->partialReset();
610 play->resetMIDI();
611 }
612
opn2_totalTimeLength(struct OPN2_MIDIPlayer * device)613 OPNMIDI_EXPORT double opn2_totalTimeLength(struct OPN2_MIDIPlayer *device)
614 {
615 #ifndef OPNMIDI_DISABLE_MIDI_SEQUENCER
616 if(!device)
617 return -1.0;
618 MidiPlayer *play = GET_MIDI_PLAYER(device);
619 assert(play);
620 return play->m_sequencer->timeLength();
621 #else
622 ADL_UNUSED(device);
623 return -1.0;
624 #endif
625 }
626
opn2_loopStartTime(struct OPN2_MIDIPlayer * device)627 OPNMIDI_EXPORT double opn2_loopStartTime(struct OPN2_MIDIPlayer *device)
628 {
629 #ifndef OPNMIDI_DISABLE_MIDI_SEQUENCER
630 if(!device)
631 return -1.0;
632 MidiPlayer *play = GET_MIDI_PLAYER(device);
633 assert(play);
634 return play->m_sequencer->getLoopStart();
635 #else
636 ADL_UNUSED(device);
637 return -1.0;
638 #endif
639 }
640
opn2_loopEndTime(struct OPN2_MIDIPlayer * device)641 OPNMIDI_EXPORT double opn2_loopEndTime(struct OPN2_MIDIPlayer *device)
642 {
643 #ifndef OPNMIDI_DISABLE_MIDI_SEQUENCER
644 if(!device)
645 return -1.0;
646 MidiPlayer *play = GET_MIDI_PLAYER(device);
647 assert(play);
648 return play->m_sequencer->getLoopEnd();
649 #else
650 ADL_UNUSED(device);
651 return -1.0;
652 #endif
653 }
654
opn2_positionTell(struct OPN2_MIDIPlayer * device)655 OPNMIDI_EXPORT double opn2_positionTell(struct OPN2_MIDIPlayer *device)
656 {
657 #ifndef OPNMIDI_DISABLE_MIDI_SEQUENCER
658 if(!device)
659 return -1.0;
660 MidiPlayer *play = GET_MIDI_PLAYER(device);
661 assert(play);
662 return play->m_sequencer->tell();
663 #else
664 ADL_UNUSED(device);
665 return -1.0;
666 #endif
667 }
668
opn2_positionSeek(struct OPN2_MIDIPlayer * device,double seconds)669 OPNMIDI_EXPORT void opn2_positionSeek(struct OPN2_MIDIPlayer *device, double seconds)
670 {
671 #ifndef OPNMIDI_DISABLE_MIDI_SEQUENCER
672 if(seconds < 0.0)
673 return;//Seeking negative position is forbidden! :-P
674 if(!device)
675 return;
676 MidiPlayer *play = GET_MIDI_PLAYER(device);
677 assert(play);
678 play->realTime_panic();
679 play->m_setup.delay = play->m_sequencer->seek(seconds, play->m_setup.mindelay);
680 play->m_setup.carry = 0.0;
681 #else
682 ADL_UNUSED(device);
683 ADL_UNUSED(seconds);
684 #endif
685 }
686
opn2_positionRewind(struct OPN2_MIDIPlayer * device)687 OPNMIDI_EXPORT void opn2_positionRewind(struct OPN2_MIDIPlayer *device)
688 {
689 #ifndef OPNMIDI_DISABLE_MIDI_SEQUENCER
690 if(!device)
691 return;
692 MidiPlayer *play = GET_MIDI_PLAYER(device);
693 assert(play);
694 play->realTime_panic();
695 play->m_sequencer->rewind();
696 #else
697 ADL_UNUSED(device);
698 #endif
699 }
700
opn2_setTempo(struct OPN2_MIDIPlayer * device,double tempo)701 OPNMIDI_EXPORT void opn2_setTempo(struct OPN2_MIDIPlayer *device, double tempo)
702 {
703 #ifndef OPNMIDI_DISABLE_MIDI_SEQUENCER
704 if(!device || (tempo <= 0.0))
705 return;
706 MidiPlayer *play = GET_MIDI_PLAYER(device);
707 assert(play);
708 play->m_sequencer->setTempo(tempo);
709 #else
710 ADL_UNUSED(device);
711 ADL_UNUSED(tempo);
712 #endif
713 }
714
715
opn2_describeChannels(struct OPN2_MIDIPlayer * device,char * str,char * attr,size_t size)716 OPNMIDI_EXPORT int opn2_describeChannels(struct OPN2_MIDIPlayer *device, char *str, char *attr, size_t size)
717 {
718 if(!device)
719 return -1;
720 MidiPlayer *play = GET_MIDI_PLAYER(device);
721 assert(play);
722 play->describeChannels(str, attr, size);
723 return 0;
724 }
725
726
opn2_metaMusicTitle(struct OPN2_MIDIPlayer * device)727 OPNMIDI_EXPORT const char *opn2_metaMusicTitle(struct OPN2_MIDIPlayer *device)
728 {
729 #ifndef OPNMIDI_DISABLE_MIDI_SEQUENCER
730 if(!device)
731 return "";
732 MidiPlayer *play = GET_MIDI_PLAYER(device);
733 assert(play);
734 return play->m_sequencer->getMusicTitle().c_str();
735 #else
736 ADL_UNUSED(device);
737 return "";
738 #endif
739 }
740
741
opn2_metaMusicCopyright(struct OPN2_MIDIPlayer * device)742 OPNMIDI_EXPORT const char *opn2_metaMusicCopyright(struct OPN2_MIDIPlayer *device)
743 {
744 #ifndef OPNMIDI_DISABLE_MIDI_SEQUENCER
745 if(!device)
746 return "";
747 MidiPlayer *play = GET_MIDI_PLAYER(device);
748 assert(play);
749 return play->m_sequencer->getMusicCopyright().c_str();
750 #else
751 ADL_UNUSED(device);
752 return 0;
753 #endif
754 }
755
opn2_metaTrackTitleCount(struct OPN2_MIDIPlayer * device)756 OPNMIDI_EXPORT size_t opn2_metaTrackTitleCount(struct OPN2_MIDIPlayer *device)
757 {
758 #ifndef OPNMIDI_DISABLE_MIDI_SEQUENCER
759 if(!device)
760 return 0;
761 MidiPlayer *play = GET_MIDI_PLAYER(device);
762 assert(play);
763 return play->m_sequencer->getTrackTitles().size();
764 #else
765 ADL_UNUSED(device);
766 return 0;
767 #endif
768 }
769
opn2_metaTrackTitle(struct OPN2_MIDIPlayer * device,size_t index)770 OPNMIDI_EXPORT const char *opn2_metaTrackTitle(struct OPN2_MIDIPlayer *device, size_t index)
771 {
772 #ifndef OPNMIDI_DISABLE_MIDI_SEQUENCER
773 if(!device)
774 return "";
775 MidiPlayer *play = GET_MIDI_PLAYER(device);
776 assert(play);
777 const std::vector<std::string> &titles = play->m_sequencer->getTrackTitles();
778 if(index >= titles.size())
779 return "INVALID";
780 return titles[index].c_str();
781 #else
782 ADL_UNUSED(device);
783 ADL_UNUSED(index);
784 return "NOT SUPPORTED";
785 #endif
786 }
787
788
opn2_metaMarkerCount(struct OPN2_MIDIPlayer * device)789 OPNMIDI_EXPORT size_t opn2_metaMarkerCount(struct OPN2_MIDIPlayer *device)
790 {
791 #ifndef OPNMIDI_DISABLE_MIDI_SEQUENCER
792 if(!device)
793 return 0;
794 MidiPlayer *play = GET_MIDI_PLAYER(device);
795 assert(play);
796 return play->m_sequencer->getMarkers().size();
797 #else
798 ADL_UNUSED(device);
799 return 0;
800 #endif
801 }
802
opn2_metaMarker(struct OPN2_MIDIPlayer * device,size_t index)803 OPNMIDI_EXPORT Opn2_MarkerEntry opn2_metaMarker(struct OPN2_MIDIPlayer *device, size_t index)
804 {
805 struct Opn2_MarkerEntry marker;
806
807 #ifndef OPNMIDI_DISABLE_MIDI_SEQUENCER
808 if(!device)
809 {
810 marker.label = "INVALID";
811 marker.pos_time = 0.0;
812 marker.pos_ticks = 0;
813 return marker;
814 }
815
816 MidiPlayer *play = GET_MIDI_PLAYER(device);
817 assert(play);
818
819 const std::vector<MidiSequencer::MIDI_MarkerEntry> &markers = play->m_sequencer->getMarkers();
820 if(index >= markers.size())
821 {
822 marker.label = "INVALID";
823 marker.pos_time = 0.0;
824 marker.pos_ticks = 0;
825 return marker;
826 }
827
828 const MidiSequencer::MIDI_MarkerEntry &mk = markers[index];
829 marker.label = mk.label.c_str();
830 marker.pos_time = mk.pos_time;
831 marker.pos_ticks = (unsigned long)mk.pos_ticks;
832 #else
833 (void)device; (void)index;
834 marker.label = "NOT SUPPORTED";
835 marker.pos_time = 0.0;
836 marker.pos_ticks = 0;
837 #endif
838 return marker;
839 }
840
opn2_setRawEventHook(struct OPN2_MIDIPlayer * device,OPN2_RawEventHook rawEventHook,void * userData)841 OPNMIDI_EXPORT void opn2_setRawEventHook(struct OPN2_MIDIPlayer *device, OPN2_RawEventHook rawEventHook, void *userData)
842 {
843 #ifndef OPNMIDI_DISABLE_MIDI_SEQUENCER
844 if(!device)
845 return;
846 MidiPlayer *play = GET_MIDI_PLAYER(device);
847 assert(play);
848 play->m_sequencerInterface->onEvent = rawEventHook;
849 play->m_sequencerInterface->onEvent_userData = userData;
850 #else
851 ADL_UNUSED(device);
852 ADL_UNUSED(rawEventHook);
853 ADL_UNUSED(userData);
854 #endif
855 }
856
857 /* Set note hook */
opn2_setNoteHook(struct OPN2_MIDIPlayer * device,OPN2_NoteHook noteHook,void * userData)858 OPNMIDI_EXPORT void opn2_setNoteHook(struct OPN2_MIDIPlayer *device, OPN2_NoteHook noteHook, void *userData)
859 {
860 if(!device)
861 return;
862 MidiPlayer *play = GET_MIDI_PLAYER(device);
863 assert(play);
864 play->hooks.onNote = noteHook;
865 play->hooks.onNote_userData = userData;
866 }
867
868 /* Set debug message hook */
opn2_setDebugMessageHook(struct OPN2_MIDIPlayer * device,OPN2_DebugMessageHook debugMessageHook,void * userData)869 OPNMIDI_EXPORT void opn2_setDebugMessageHook(struct OPN2_MIDIPlayer *device, OPN2_DebugMessageHook debugMessageHook, void *userData)
870 {
871 if(!device)
872 return;
873 MidiPlayer *play = GET_MIDI_PLAYER(device);
874 assert(play);
875 play->hooks.onDebugMessage = debugMessageHook;
876 play->hooks.onDebugMessage_userData = userData;
877 #ifndef OPNMIDI_DISABLE_MIDI_SEQUENCER
878 play->m_sequencerInterface->onDebugMessage = debugMessageHook;
879 play->m_sequencerInterface->onDebugMessage_userData = userData;
880 #endif
881 }
882
883
884 template <class Dst>
CopySamplesRaw(OPN2_UInt8 * dstLeft,OPN2_UInt8 * dstRight,const int32_t * src,size_t frameCount,unsigned sampleOffset)885 static void CopySamplesRaw(OPN2_UInt8 *dstLeft, OPN2_UInt8 *dstRight, const int32_t *src,
886 size_t frameCount, unsigned sampleOffset)
887 {
888 for(size_t i = 0; i < frameCount; ++i) {
889 *(Dst *)(dstLeft + (i * sampleOffset)) = src[2 * i];
890 *(Dst *)(dstRight + (i * sampleOffset)) = src[(2 * i) + 1];
891 }
892 }
893
894 template <class Dst, class Ret>
CopySamplesTransformed(OPN2_UInt8 * dstLeft,OPN2_UInt8 * dstRight,const int32_t * src,size_t frameCount,unsigned sampleOffset,Ret (& transform)(int32_t))895 static void CopySamplesTransformed(OPN2_UInt8 *dstLeft, OPN2_UInt8 *dstRight, const int32_t *src,
896 size_t frameCount, unsigned sampleOffset,
897 Ret(&transform)(int32_t))
898 {
899 for(size_t i = 0; i < frameCount; ++i) {
900 *(Dst *)(dstLeft + (i * sampleOffset)) = static_cast<Dst>(transform(src[2 * i]));
901 *(Dst *)(dstRight + (i * sampleOffset)) = static_cast<Dst>(transform(src[(2 * i) + 1]));
902 }
903 }
904
SendStereoAudio(int samples_requested,ssize_t in_size,int32_t * _in,ssize_t out_pos,OPN2_UInt8 * left,OPN2_UInt8 * right,const OPNMIDI_AudioFormat * format)905 static int SendStereoAudio(int samples_requested,
906 ssize_t in_size,
907 int32_t *_in,
908 ssize_t out_pos,
909 OPN2_UInt8 *left,
910 OPN2_UInt8 *right,
911 const OPNMIDI_AudioFormat *format)
912 {
913 if(!in_size)
914 return 0;
915 size_t outputOffset = static_cast<size_t>(out_pos);
916 size_t inSamples = static_cast<size_t>(in_size * 2);
917 size_t maxSamples = static_cast<size_t>(samples_requested) - outputOffset;
918 size_t toCopy = std::min(maxSamples, inSamples);
919
920 OPNMIDI_SampleType sampleType = format->type;
921 const unsigned containerSize = format->containerSize;
922 const unsigned sampleOffset = format->sampleOffset;
923
924 left += (outputOffset / 2) * sampleOffset;
925 right += (outputOffset / 2) * sampleOffset;
926
927 typedef int32_t(&pfnConvert)(int32_t);
928
929 switch(sampleType) {
930 case OPNMIDI_SampleType_S8:
931 case OPNMIDI_SampleType_U8:
932 {
933 pfnConvert cvt = (sampleType == OPNMIDI_SampleType_S8) ? opn2_cvtS8 : opn2_cvtU8;
934 switch(containerSize) {
935 case sizeof(int8_t):
936 CopySamplesTransformed<int8_t>(left, right, _in, toCopy / 2, sampleOffset, cvt);
937 break;
938 case sizeof(int16_t):
939 CopySamplesTransformed<int16_t>(left, right, _in, toCopy / 2, sampleOffset, cvt);
940 break;
941 case sizeof(int32_t):
942 CopySamplesTransformed<int32_t>(left, right, _in, toCopy / 2, sampleOffset, cvt);
943 break;
944 default:
945 return -1;
946 }
947 break;
948 }
949 case OPNMIDI_SampleType_S16:
950 case OPNMIDI_SampleType_U16:
951 {
952 pfnConvert cvt = (sampleType == OPNMIDI_SampleType_S16) ? opn2_cvtS16 : opn2_cvtU16;
953 switch(containerSize) {
954 case sizeof(int16_t):
955 CopySamplesTransformed<int16_t>(left, right, _in, toCopy / 2, sampleOffset, cvt);
956 break;
957 case sizeof(int32_t):
958 CopySamplesRaw<int32_t>(left, right, _in, toCopy / 2, sampleOffset);
959 break;
960 default:
961 return -1;
962 }
963 break;
964 }
965 case OPNMIDI_SampleType_S24:
966 case OPNMIDI_SampleType_U24:
967 {
968 pfnConvert cvt = (sampleType == OPNMIDI_SampleType_S24) ? opn2_cvtS24 : opn2_cvtU24;
969 switch(containerSize) {
970 case sizeof(int32_t):
971 CopySamplesTransformed<int32_t>(left, right, _in, toCopy / 2, sampleOffset, cvt);
972 break;
973 default:
974 return -1;
975 }
976 break;
977 }
978 case OPNMIDI_SampleType_S32:
979 case OPNMIDI_SampleType_U32:
980 {
981 pfnConvert cvt = (sampleType == OPNMIDI_SampleType_S32) ? opn2_cvtS32 : opn2_cvtU32;
982 switch(containerSize) {
983 case sizeof(int32_t):
984 CopySamplesTransformed<int32_t>(left, right, _in, toCopy / 2, sampleOffset, cvt);
985 break;
986 default:
987 return -1;
988 }
989 break;
990 }
991 case OPNMIDI_SampleType_F32:
992 if(containerSize != sizeof(float))
993 return -1;
994 CopySamplesTransformed<float>(left, right, _in, toCopy / 2, sampleOffset, opn2_cvtReal<float>);
995 break;
996 case OPNMIDI_SampleType_F64:
997 if(containerSize != sizeof(double))
998 return -1;
999 CopySamplesTransformed<double>(left, right, _in, toCopy / 2, sampleOffset, opn2_cvtReal<double>);
1000 break;
1001 default:
1002 return -1;
1003 }
1004
1005 return 0;
1006 }
1007
1008
opn2_play(struct OPN2_MIDIPlayer * device,int sampleCount,short * out)1009 OPNMIDI_EXPORT int opn2_play(struct OPN2_MIDIPlayer *device, int sampleCount, short *out)
1010 {
1011 return opn2_playFormat(device, sampleCount, (OPN2_UInt8 *)out, (OPN2_UInt8 *)(out + 1), &opn2_DefaultAudioFormat);
1012 }
1013
opn2_playFormat(OPN2_MIDIPlayer * device,int sampleCount,OPN2_UInt8 * out_left,OPN2_UInt8 * out_right,const OPNMIDI_AudioFormat * format)1014 OPNMIDI_EXPORT int opn2_playFormat(OPN2_MIDIPlayer *device, int sampleCount,
1015 OPN2_UInt8 *out_left, OPN2_UInt8 *out_right,
1016 const OPNMIDI_AudioFormat *format)
1017 {
1018 #if defined(OPNMIDI_DISABLE_MIDI_SEQUENCER)
1019 ADL_UNUSED(device);
1020 ADL_UNUSED(sampleCount);
1021 ADL_UNUSED(out_left);
1022 ADL_UNUSED(out_right);
1023 ADL_UNUSED(format);
1024 return 0;
1025 #endif
1026
1027 #ifndef OPNMIDI_DISABLE_MIDI_SEQUENCER
1028 sampleCount -= sampleCount % 2; //Avoid even sample requests
1029 if(sampleCount < 0)
1030 return 0;
1031 if(!device)
1032 return 0;
1033
1034 MidiPlayer *player = GET_MIDI_PLAYER(device);
1035 assert(player);
1036 MidiPlayer::Setup &setup = player->m_setup;
1037
1038 ssize_t gotten_len = 0;
1039 ssize_t n_periodCountStereo = 512;
1040 //ssize_t n_periodCountPhys = n_periodCountStereo * 2;
1041 int left = sampleCount;
1042 bool hasSkipped = setup.tick_skip_samples_delay > 0;
1043
1044 while(left > 0)
1045 {
1046 {//
1047 if(setup.delay <= 0.0)
1048 setup.delay = double(left / 2) / double(setup.PCM_RATE);
1049 const double eat_delay = setup.delay < setup.maxdelay ? setup.delay : setup.maxdelay;
1050 if(hasSkipped)
1051 {
1052 size_t samples = setup.tick_skip_samples_delay > sampleCount ? sampleCount : setup.tick_skip_samples_delay;
1053 n_periodCountStereo = samples / 2;
1054 }
1055 else
1056 {
1057 setup.delay -= eat_delay;
1058 setup.carry += double(setup.PCM_RATE) * eat_delay;
1059 n_periodCountStereo = static_cast<ssize_t>(setup.carry);
1060 setup.carry -= double(n_periodCountStereo);
1061 }
1062
1063 //if(setup.SkipForward > 0)
1064 // setup.SkipForward -= 1;
1065 //else
1066 {
1067 if((player->m_sequencer->positionAtEnd()) && (setup.delay <= 0.0))
1068 break;//Stop to fetch samples at reaching the song end with disabled loop
1069
1070 ssize_t leftSamples = left / 2;
1071 if(n_periodCountStereo > leftSamples)
1072 {
1073 setup.tick_skip_samples_delay = (n_periodCountStereo - leftSamples) * 2;
1074 n_periodCountStereo = leftSamples;
1075 }
1076 //! Count of stereo samples
1077 ssize_t in_generatedStereo = (n_periodCountStereo > 512) ? 512 : n_periodCountStereo;
1078 //! Total count of samples
1079 ssize_t in_generatedPhys = in_generatedStereo * 2;
1080 //! Unsigned total sample count
1081 //fill buffer with zeros
1082 int32_t *out_buf = player->m_outBuf;
1083 std::memset(out_buf, 0, static_cast<size_t>(in_generatedPhys) * sizeof(out_buf[0]));
1084 Synth &synth = *player->m_synth;
1085 unsigned int chips = synth.m_numChips;
1086 if(chips == 1)
1087 synth.m_chips[0]->generate32(out_buf, (size_t)in_generatedStereo);
1088 else/* if(n_periodCountStereo > 0)*/
1089 {
1090 /* Generate data from every chip and mix result */
1091 for(size_t card = 0; card < chips; ++card)
1092 synth.m_chips[card]->generateAndMix32(out_buf, (size_t)in_generatedStereo);
1093 }
1094 /* Process it */
1095 if(SendStereoAudio(sampleCount, in_generatedStereo, out_buf, gotten_len, out_left, out_right, format) == -1)
1096 return 0;
1097
1098 left -= (int)in_generatedPhys;
1099 gotten_len += (in_generatedPhys) /* - setup.stored_samples*/;
1100 }
1101 if(hasSkipped)
1102 {
1103 setup.tick_skip_samples_delay -= n_periodCountStereo * 2;
1104 hasSkipped = setup.tick_skip_samples_delay > 0;
1105 }
1106 else
1107 setup.delay = player->Tick(eat_delay, setup.mindelay);
1108 }//
1109 }
1110
1111 return static_cast<int>(gotten_len);
1112 #endif //OPNMIDI_DISABLE_MIDI_SEQUENCER
1113 }
1114
1115
opn2_generate(struct OPN2_MIDIPlayer * device,int sampleCount,short * out)1116 OPNMIDI_EXPORT int opn2_generate(struct OPN2_MIDIPlayer *device, int sampleCount, short *out)
1117 {
1118 return opn2_generateFormat(device, sampleCount, (OPN2_UInt8 *)out, (OPN2_UInt8 *)(out + 1), &opn2_DefaultAudioFormat);
1119 }
1120
opn2_generateFormat(struct OPN2_MIDIPlayer * device,int sampleCount,OPN2_UInt8 * out_left,OPN2_UInt8 * out_right,const OPNMIDI_AudioFormat * format)1121 OPNMIDI_EXPORT int opn2_generateFormat(struct OPN2_MIDIPlayer *device, int sampleCount,
1122 OPN2_UInt8 *out_left, OPN2_UInt8 *out_right,
1123 const OPNMIDI_AudioFormat *format)
1124 {
1125 sampleCount -= sampleCount % 2; //Avoid even sample requests
1126 if(sampleCount < 0)
1127 return 0;
1128 if(!device)
1129 return 0;
1130
1131 MidiPlayer *player = GET_MIDI_PLAYER(device);
1132 assert(player);
1133 MidiPlayer::Setup &setup = player->m_setup;
1134
1135 ssize_t gotten_len = 0;
1136 ssize_t n_periodCountStereo = 512;
1137
1138 int left = sampleCount;
1139 double delay = double(sampleCount / 2) / double(setup.PCM_RATE);
1140
1141 while(left > 0)
1142 {
1143 {//
1144 if(delay <= 0.0)
1145 delay = double(left / 2) / double(setup.PCM_RATE);
1146 const double eat_delay = delay < setup.maxdelay ? delay : setup.maxdelay;
1147 delay -= eat_delay;
1148 setup.carry += double(setup.PCM_RATE) * eat_delay;
1149 n_periodCountStereo = static_cast<ssize_t>(setup.carry);
1150 setup.carry -= double(n_periodCountStereo);
1151
1152 {
1153 ssize_t leftSamples = left / 2;
1154 if(n_periodCountStereo > leftSamples)
1155 n_periodCountStereo = leftSamples;
1156 //! Count of stereo samples
1157 ssize_t in_generatedStereo = (n_periodCountStereo > 512) ? 512 : n_periodCountStereo;
1158 //! Total count of samples
1159 ssize_t in_generatedPhys = in_generatedStereo * 2;
1160 //! Unsigned total sample count
1161 //fill buffer with zeros
1162 int32_t *out_buf = player->m_outBuf;
1163 std::memset(out_buf, 0, static_cast<size_t>(in_generatedPhys) * sizeof(out_buf[0]));
1164 Synth &synth = *player->m_synth;
1165 unsigned int chips = synth.m_numChips;
1166 if(chips == 1)
1167 synth.m_chips[0]->generate32(out_buf, (size_t)in_generatedStereo);
1168 else/* if(n_periodCountStereo > 0)*/
1169 {
1170 /* Generate data from every chip and mix result */
1171 for(size_t card = 0; card < chips; ++card)
1172 synth.m_chips[card]->generateAndMix32(out_buf, (size_t)in_generatedStereo);
1173 }
1174 /* Process it */
1175 if(SendStereoAudio(sampleCount, in_generatedStereo, out_buf, gotten_len, out_left, out_right, format) == -1)
1176 return 0;
1177
1178 left -= (int)in_generatedPhys;
1179 gotten_len += (in_generatedPhys) /* - setup.stored_samples*/;
1180 }
1181
1182 player->TickIterators(eat_delay);
1183 }//...
1184 }
1185
1186 return static_cast<int>(gotten_len);
1187 }
1188
opn2_tickEvents(struct OPN2_MIDIPlayer * device,double seconds,double granuality)1189 OPNMIDI_EXPORT double opn2_tickEvents(struct OPN2_MIDIPlayer *device, double seconds, double granuality)
1190 {
1191 #ifndef OPNMIDI_DISABLE_MIDI_SEQUENCER
1192 if(!device)
1193 return -1.0;
1194 MidiPlayer *play = GET_MIDI_PLAYER(device);
1195 assert(play);
1196 return play->Tick(seconds, granuality);
1197 #else
1198 ADL_UNUSED(device);
1199 ADL_UNUSED(seconds);
1200 ADL_UNUSED(granuality);
1201 return -1.0;
1202 #endif
1203 }
1204
opn2_atEnd(struct OPN2_MIDIPlayer * device)1205 OPNMIDI_EXPORT int opn2_atEnd(struct OPN2_MIDIPlayer *device)
1206 {
1207 #ifndef OPNMIDI_DISABLE_MIDI_SEQUENCER
1208 if(!device)
1209 return 1;
1210 MidiPlayer *play = GET_MIDI_PLAYER(device);
1211 assert(play);
1212 return (int)play->m_sequencer->positionAtEnd();
1213 #else
1214 ADL_UNUSED(device);
1215 return 1;
1216 #endif
1217 }
1218
opn2_trackCount(struct OPN2_MIDIPlayer * device)1219 OPNMIDI_EXPORT size_t opn2_trackCount(struct OPN2_MIDIPlayer *device)
1220 {
1221 #ifndef OPNMIDI_DISABLE_MIDI_SEQUENCER
1222 if(!device)
1223 return 0;
1224 MidiPlayer *play = GET_MIDI_PLAYER(device);
1225 assert(play);
1226 return play->m_sequencer->getTrackCount();
1227 #else
1228 ADL_UNUSED(device);
1229 return 0;
1230 #endif
1231 }
1232
opn2_setTrackOptions(struct OPN2_MIDIPlayer * device,size_t trackNumber,unsigned trackOptions)1233 OPNMIDI_EXPORT int opn2_setTrackOptions(struct OPN2_MIDIPlayer *device, size_t trackNumber, unsigned trackOptions)
1234 {
1235 #ifndef OPNMIDI_DISABLE_MIDI_SEQUENCER
1236 if(!device)
1237 return -1;
1238 MidiPlayer *play = GET_MIDI_PLAYER(device);
1239 assert(play);
1240 MidiSequencer &seq = *play->m_sequencer;
1241
1242 unsigned enableFlag = trackOptions & 3;
1243 trackOptions &= ~3u;
1244
1245 // handle on/off/solo
1246 switch(enableFlag)
1247 {
1248 default:
1249 break;
1250 case OPNMIDI_TrackOption_On:
1251 case OPNMIDI_TrackOption_Off:
1252 if(!seq.setTrackEnabled(trackNumber, enableFlag == OPNMIDI_TrackOption_On))
1253 return -1;
1254 break;
1255 case OPNMIDI_TrackOption_Solo:
1256 seq.setSoloTrack(trackNumber);
1257 break;
1258 }
1259
1260 // handle others...
1261 if(trackOptions != 0)
1262 return -1;
1263
1264 return 0;
1265
1266 #else
1267 ADL_UNUSED(device);
1268 ADL_UNUSED(trackNumber);
1269 ADL_UNUSED(trackOptions);
1270 return -1;
1271 #endif
1272 }
1273
opn2_panic(struct OPN2_MIDIPlayer * device)1274 OPNMIDI_EXPORT void opn2_panic(struct OPN2_MIDIPlayer *device)
1275 {
1276 if(!device)
1277 return;
1278 MidiPlayer *play = GET_MIDI_PLAYER(device);
1279 assert(play);
1280 play->realTime_panic();
1281 }
1282
opn2_rt_resetState(struct OPN2_MIDIPlayer * device)1283 OPNMIDI_EXPORT void opn2_rt_resetState(struct OPN2_MIDIPlayer *device)
1284 {
1285 if(!device)
1286 return;
1287 MidiPlayer *play = GET_MIDI_PLAYER(device);
1288 assert(play);
1289 play->realTime_ResetState();
1290 }
1291
opn2_rt_noteOn(struct OPN2_MIDIPlayer * device,OPN2_UInt8 channel,OPN2_UInt8 note,OPN2_UInt8 velocity)1292 OPNMIDI_EXPORT int opn2_rt_noteOn(struct OPN2_MIDIPlayer *device, OPN2_UInt8 channel, OPN2_UInt8 note, OPN2_UInt8 velocity)
1293 {
1294 if(!device)
1295 return 0;
1296 MidiPlayer *play = GET_MIDI_PLAYER(device);
1297 assert(play);
1298 return (int)play->realTime_NoteOn(channel, note, velocity);
1299 }
1300
opn2_rt_noteOff(struct OPN2_MIDIPlayer * device,OPN2_UInt8 channel,OPN2_UInt8 note)1301 OPNMIDI_EXPORT void opn2_rt_noteOff(struct OPN2_MIDIPlayer *device, OPN2_UInt8 channel, OPN2_UInt8 note)
1302 {
1303 if(!device)
1304 return;
1305 MidiPlayer *play = GET_MIDI_PLAYER(device);
1306 assert(play);
1307 play->realTime_NoteOff(channel, note);
1308 }
1309
opn2_rt_noteAfterTouch(struct OPN2_MIDIPlayer * device,OPN2_UInt8 channel,OPN2_UInt8 note,OPN2_UInt8 atVal)1310 OPNMIDI_EXPORT void opn2_rt_noteAfterTouch(struct OPN2_MIDIPlayer *device, OPN2_UInt8 channel, OPN2_UInt8 note, OPN2_UInt8 atVal)
1311 {
1312 if(!device)
1313 return;
1314 MidiPlayer *play = GET_MIDI_PLAYER(device);
1315 assert(play);
1316 play->realTime_NoteAfterTouch(channel, note, atVal);
1317 }
1318
opn2_rt_channelAfterTouch(struct OPN2_MIDIPlayer * device,OPN2_UInt8 channel,OPN2_UInt8 atVal)1319 OPNMIDI_EXPORT void opn2_rt_channelAfterTouch(struct OPN2_MIDIPlayer *device, OPN2_UInt8 channel, OPN2_UInt8 atVal)
1320 {
1321 if(!device)
1322 return;
1323 MidiPlayer *play = GET_MIDI_PLAYER(device);
1324 assert(play);
1325 play->realTime_ChannelAfterTouch(channel, atVal);
1326 }
1327
opn2_rt_controllerChange(struct OPN2_MIDIPlayer * device,OPN2_UInt8 channel,OPN2_UInt8 type,OPN2_UInt8 value)1328 OPNMIDI_EXPORT void opn2_rt_controllerChange(struct OPN2_MIDIPlayer *device, OPN2_UInt8 channel, OPN2_UInt8 type, OPN2_UInt8 value)
1329 {
1330 if(!device)
1331 return;
1332 MidiPlayer *play = GET_MIDI_PLAYER(device);
1333 assert(play);
1334 play->realTime_Controller(channel, type, value);
1335 }
1336
opn2_rt_patchChange(struct OPN2_MIDIPlayer * device,OPN2_UInt8 channel,OPN2_UInt8 patch)1337 OPNMIDI_EXPORT void opn2_rt_patchChange(struct OPN2_MIDIPlayer *device, OPN2_UInt8 channel, OPN2_UInt8 patch)
1338 {
1339 if(!device)
1340 return;
1341 MidiPlayer *play = GET_MIDI_PLAYER(device);
1342 assert(play);
1343 play->realTime_PatchChange(channel, patch);
1344 }
1345
opn2_rt_pitchBend(struct OPN2_MIDIPlayer * device,OPN2_UInt8 channel,OPN2_UInt16 pitch)1346 OPNMIDI_EXPORT void opn2_rt_pitchBend(struct OPN2_MIDIPlayer *device, OPN2_UInt8 channel, OPN2_UInt16 pitch)
1347 {
1348 if(!device)
1349 return;
1350 MidiPlayer *play = GET_MIDI_PLAYER(device);
1351 assert(play);
1352 play->realTime_PitchBend(channel, pitch);
1353 }
1354
opn2_rt_pitchBendML(struct OPN2_MIDIPlayer * device,OPN2_UInt8 channel,OPN2_UInt8 msb,OPN2_UInt8 lsb)1355 OPNMIDI_EXPORT void opn2_rt_pitchBendML(struct OPN2_MIDIPlayer *device, OPN2_UInt8 channel, OPN2_UInt8 msb, OPN2_UInt8 lsb)
1356 {
1357 if(!device)
1358 return;
1359 MidiPlayer *play = GET_MIDI_PLAYER(device);
1360 assert(play);
1361 play->realTime_PitchBend(channel, msb, lsb);
1362 }
1363
opn2_rt_bankChangeLSB(struct OPN2_MIDIPlayer * device,OPN2_UInt8 channel,OPN2_UInt8 lsb)1364 OPNMIDI_EXPORT void opn2_rt_bankChangeLSB(struct OPN2_MIDIPlayer *device, OPN2_UInt8 channel, OPN2_UInt8 lsb)
1365 {
1366 if(!device)
1367 return;
1368 MidiPlayer *play = GET_MIDI_PLAYER(device);
1369 assert(play);
1370 play->realTime_BankChangeLSB(channel, lsb);
1371 }
1372
opn2_rt_bankChangeMSB(struct OPN2_MIDIPlayer * device,OPN2_UInt8 channel,OPN2_UInt8 msb)1373 OPNMIDI_EXPORT void opn2_rt_bankChangeMSB(struct OPN2_MIDIPlayer *device, OPN2_UInt8 channel, OPN2_UInt8 msb)
1374 {
1375 if(!device)
1376 return;
1377 MidiPlayer *play = GET_MIDI_PLAYER(device);
1378 assert(play);
1379 play->realTime_BankChangeMSB(channel, msb);
1380 }
1381
opn2_rt_bankChange(struct OPN2_MIDIPlayer * device,OPN2_UInt8 channel,OPN2_SInt16 bank)1382 OPNMIDI_EXPORT void opn2_rt_bankChange(struct OPN2_MIDIPlayer *device, OPN2_UInt8 channel, OPN2_SInt16 bank)
1383 {
1384 if(!device)
1385 return;
1386 MidiPlayer *play = GET_MIDI_PLAYER(device);
1387 assert(play);
1388 play->realTime_BankChange(channel, (uint16_t)bank);
1389 }
1390
opn2_rt_systemExclusive(struct OPN2_MIDIPlayer * device,const OPN2_UInt8 * msg,size_t size)1391 OPNMIDI_EXPORT int opn2_rt_systemExclusive(struct OPN2_MIDIPlayer *device, const OPN2_UInt8 *msg, size_t size)
1392 {
1393 if(!device)
1394 return -1;
1395 MidiPlayer *play = GET_MIDI_PLAYER(device);
1396 assert(play);
1397 return play->realTime_SysEx(msg, size);
1398 }
1399