1 /*
2  * Copyright (C) 2018-2020 Rerrah
3  *
4  * Permission is hereby granted, free of charge, to any person
5  * obtaining a copy of this software and associated documentation
6  * files (the "Software"), to deal in the Software without
7  * restriction, including without limitation the rights to use,
8  * copy, modify, merge, publish, distribute, sublicense, and/or sell
9  * copies of the Software, and to permit persons to whom the
10  * Software is furnished to do so, subject to the following
11  * conditions:
12  *
13  * The above copyright notice and this permission notice shall be
14  * included in all copies or substantial portions of the Software.
15  *
16  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
18  * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19  * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
20  * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
21  * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
22  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
23  * OTHER DEALINGS IN THE SOFTWARE.
24  */
25 
26 #include "bamboo_tracker.hpp"
27 #include <algorithm>
28 #include <utility>
29 #include <unordered_set>
30 #include <exception>
31 #include <unordered_map>
32 #include "commands.hpp"
33 #include "io_handlers.hpp"
34 #include "bank.hpp"
35 #include "song_length_calculator.hpp"
36 
37 const uint32_t BambooTracker::CHIP_CLOCK = 3993600 * 2;
38 
BambooTracker(std::weak_ptr<Configuration> config)39 BambooTracker::BambooTracker(std::weak_ptr<Configuration> config)
40 	: instMan_(std::make_shared<InstrumentsManager>(config.lock()->getOverwriteUnusedUneditedPropety())),
41 	  tickCounter_(std::make_shared<TickCounter>()),
42 	  mod_(std::make_shared<Module>()),
43 	  curOctave_(4),
44 	  curSongNum_(0),
45 	  curTrackNum_(0),
46 	  curOrderNum_(0),
47 	  curStepNum_(0),
48 	  curInstNum_(-1),
49 	  curVolume_(127),
50 	  mkOrder_(-1),
51 	  mkStep_(-1),
52 	  isFollowPlay_(true)
53 {
54 	opnaCtrl_ = std::make_shared<OPNAController>(
55 					static_cast<chip::Emu>(config.lock()->getEmulator()),
56 					CHIP_CLOCK,
57 					config.lock()->getSampleRate(),
58 					config.lock()->getBufferLength());
59 	setMasterVolume(config.lock()->getMixerVolumeMaster());
60 	setMasterVolumeFM(config.lock()->getMixerVolumeFM());
61 	setMasterVolumeSSG(config.lock()->getMixerVolumeSSG());
62 
63 	songStyle_ = mod_->getSong(curSongNum_).getStyle();
64 	jamMan_ = std::make_unique<JamManager>();
65 
66 	playback_ = std::make_unique<PlaybackManager>(
67 					opnaCtrl_, instMan_, tickCounter_, mod_, config.lock()->getRetrieveChannelState());
68 
69 	storeOnlyUsedSamples_ = config.lock()->getWriteOnlyUsedSamples();
70 	volFMReversed_ = config.lock()->getReverseFMVolumeOrder();
71 }
72 
73 /********** Change configuration **********/
changeConfiguration(std::weak_ptr<Configuration> config)74 void BambooTracker::changeConfiguration(std::weak_ptr<Configuration> config)
75 {
76 	setStreamRate(static_cast<int>(config.lock()->getSampleRate()));
77 	setStreamDuration(static_cast<int>(config.lock()->getBufferLength()));
78 	setMasterVolume(config.lock()->getMixerVolumeMaster());
79 	if (mod_->getMixerType() == MixerType::UNSPECIFIED) {
80 		setMasterVolumeFM(config.lock()->getMixerVolumeFM());
81 		setMasterVolumeSSG(config.lock()->getMixerVolumeSSG());
82 	}
83 	playback_->setChannelRetrieving(config.lock()->getRetrieveChannelState());
84 	instMan_->setPropertyFindMode(config.lock()->getOverwriteUnusedUneditedPropety());
85 	storeOnlyUsedSamples_ = config.lock()->getWriteOnlyUsedSamples();
86 	volFMReversed_ = config.lock()->getReverseFMVolumeOrder();
87 }
88 
89 /********** Current octave **********/
setCurrentOctave(int octave)90 void BambooTracker::setCurrentOctave(int octave)
91 {
92 	curOctave_ = octave;
93 }
94 
getCurrentOctave() const95 int BambooTracker::getCurrentOctave() const
96 {
97 	return curOctave_;
98 }
99 
100 /********** Current volume **********/
setCurrentVolume(int volume)101 void BambooTracker::setCurrentVolume(int volume)
102 {
103 	curVolume_ = volume;
104 }
105 
getCurrentVolume() const106 int BambooTracker::getCurrentVolume() const
107 {
108 	return curVolume_;
109 }
110 
111 /********** Current track **********/
setCurrentTrack(int num)112 void BambooTracker::setCurrentTrack(int num)
113 {
114 	curTrackNum_ = num;
115 }
116 
getCurrentTrackAttribute() const117 TrackAttribute BambooTracker::getCurrentTrackAttribute() const
118 {
119 	TrackAttribute ret = songStyle_.trackAttribs.at(static_cast<size_t>(curTrackNum_));
120 	return ret;
121 }
122 
123 /********** Current instrument **********/
setCurrentInstrument(int n)124 void BambooTracker::setCurrentInstrument(int n)
125 {
126 	curInstNum_ = n;
127 }
128 
getCurrentInstrumentNumber() const129 int BambooTracker::getCurrentInstrumentNumber() const
130 {
131 	return curInstNum_;
132 }
133 
134 /********** Instrument edit **********/
addInstrument(int num,InstrumentType type,std::string name)135 void BambooTracker::addInstrument(int num, InstrumentType type, std::string name)
136 {
137 	comMan_.invoke(std::make_unique<AddInstrumentCommand>(instMan_, num, type, name));
138 }
139 
removeInstrument(int num)140 void BambooTracker::removeInstrument(int num)
141 {
142 	comMan_.invoke(std::make_unique<RemoveInstrumentCommand>(instMan_, num));
143 }
144 
getInstrument(int num)145 std::unique_ptr<AbstractInstrument> BambooTracker::getInstrument(int num)
146 {
147 	std::shared_ptr<AbstractInstrument> inst = instMan_->getInstrumentSharedPtr(num);
148 	if (inst == nullptr) return std::unique_ptr<AbstractInstrument>();
149 	else return std::unique_ptr<AbstractInstrument>(inst->clone());
150 }
151 
cloneInstrument(int num,int refNum)152 void BambooTracker::cloneInstrument(int num, int refNum)
153 {
154 	comMan_.invoke(std::make_unique<cloneInstrumentCommand>(instMan_, num, refNum));
155 }
156 
deepCloneInstrument(int num,int refNum)157 void BambooTracker::deepCloneInstrument(int num, int refNum)
158 {
159 	comMan_.invoke(std::make_unique<DeepCloneInstrumentCommand>(instMan_, num, refNum));
160 }
161 
swapInstruments(int a,int b,bool patternChange)162 void BambooTracker::swapInstruments(int a, int b, bool patternChange)
163 {
164 	comMan_.invoke(std::make_unique<SwapInstrumentsCommand>(instMan_, mod_, a, b, curSongNum_, patternChange));
165 }
166 
loadInstrument(BinaryContainer & container,std::string path,int instNum)167 void BambooTracker::loadInstrument(BinaryContainer& container, std::string path, int instNum)
168 {
169 	auto inst = InstrumentIO::loadInstrument(container, path, instMan_, instNum);
170 	comMan_.invoke(std::make_unique<AddInstrumentCommand>(
171 					   instMan_, std::unique_ptr<AbstractInstrument>(inst)));
172 }
173 
saveInstrument(BinaryContainer & container,int instNum)174 void BambooTracker::saveInstrument(BinaryContainer& container, int instNum)
175 {
176 	InstrumentIO::saveInstrument(container, instMan_, instNum);
177 }
178 
importInstrument(const AbstractBank & bank,size_t index,int instNum)179 void BambooTracker::importInstrument(const AbstractBank &bank, size_t index, int instNum)
180 {
181 	auto inst = bank.loadInstrument(index, instMan_, instNum);
182 	comMan_.invoke(std::make_unique<AddInstrumentCommand>(
183 					   instMan_, std::unique_ptr<AbstractInstrument>(inst)));
184 }
185 
exportInstruments(BinaryContainer & container,std::vector<int> instNums)186 void BambooTracker::exportInstruments(BinaryContainer& container, std::vector<int> instNums)
187 {
188 	BankIO::saveBank(container, instNums, instMan_);
189 }
190 
findFirstFreeInstrumentNumber() const191 int BambooTracker::findFirstFreeInstrumentNumber() const
192 {
193 	return instMan_->findFirstFreeInstrument();
194 }
195 
setInstrumentName(int num,std::string name)196 void BambooTracker::setInstrumentName(int num, std::string name)
197 {
198 	comMan_.invoke(std::make_unique<ChangeInstrumentNameCommand>(instMan_, num, name));
199 }
200 
clearAllInstrument()201 void BambooTracker::clearAllInstrument()
202 {
203 	instMan_->clearAll();
204 }
205 
getInstrumentIndices() const206 std::vector<int> BambooTracker::getInstrumentIndices() const
207 {
208 	return instMan_->getInstrumentIndices();
209 }
210 
getUnusedInstrumentIndices() const211 std::vector<int> BambooTracker::getUnusedInstrumentIndices() const
212 {
213 	std::vector<int> unused;
214 	std::unordered_set<int> regdInsts = mod_->getRegisterdInstruments();
215 	for (auto& inst : instMan_->getInstrumentIndices()) {
216 		if (!regdInsts.count(inst)) unused.push_back(inst);
217 	}
218 	return unused;
219 }
220 
clearUnusedInstrumentProperties()221 void BambooTracker::clearUnusedInstrumentProperties()
222 {
223 	instMan_->clearUnusedInstrumentProperties();
224 }
225 
getInstrumentNames() const226 std::vector<std::string> BambooTracker::getInstrumentNames() const
227 {
228 	return instMan_->getInstrumentNameList();
229 }
230 
checkDuplicateInstruments() const231 std::vector<std::vector<int>> BambooTracker::checkDuplicateInstruments() const
232 {
233 	return instMan_->checkDuplicateInstruments();
234 }
235 
236 //--- FM
setEnvelopeFMParameter(int envNum,FMEnvelopeParameter param,int value)237 void BambooTracker::setEnvelopeFMParameter(int envNum, FMEnvelopeParameter param, int value)
238 {
239 	instMan_->setEnvelopeFMParameter(envNum, param, value);
240 	opnaCtrl_->updateInstrumentFMEnvelopeParameter(envNum, param);
241 }
242 
setEnvelopeFMOperatorEnable(int envNum,int opNum,bool enable)243 void BambooTracker::setEnvelopeFMOperatorEnable(int envNum, int opNum, bool enable)
244 {
245 	instMan_->setEnvelopeFMOperatorEnabled(envNum, opNum, enable);
246 	opnaCtrl_->setInstrumentFMOperatorEnabled(envNum, opNum);
247 }
248 
setInstrumentFMEnvelope(int instNum,int envNum)249 void BambooTracker::setInstrumentFMEnvelope(int instNum, int envNum)
250 {
251 	instMan_->setInstrumentFMEnvelope(instNum, envNum);
252 	opnaCtrl_->updateInstrumentFM(instNum);
253 }
254 
getEnvelopeFMUsers(int envNum) const255 std::vector<int> BambooTracker::getEnvelopeFMUsers(int envNum) const
256 {
257 	return instMan_->getEnvelopeFMUsers(envNum);
258 }
259 
setLFOFMParameter(int lfoNum,FMLFOParameter param,int value)260 void BambooTracker::setLFOFMParameter(int lfoNum, FMLFOParameter param, int value)
261 {
262 	instMan_->setLFOFMParameter(lfoNum, param, value);
263 	opnaCtrl_->updateInstrumentFMLFOParameter(lfoNum, param);
264 }
265 
setInstrumentFMLFOEnabled(int instNum,bool enabled)266 void BambooTracker::setInstrumentFMLFOEnabled(int instNum, bool enabled)
267 {
268 	instMan_->setInstrumentFMLFOEnabled(instNum, enabled);
269 	opnaCtrl_->updateInstrumentFM(instNum);
270 }
271 
setInstrumentFMLFO(int instNum,int lfoNum)272 void BambooTracker::setInstrumentFMLFO(int instNum, int lfoNum)
273 {
274 	instMan_->setInstrumentFMLFO(instNum, lfoNum);
275 	opnaCtrl_->updateInstrumentFM(instNum);
276 }
277 
getLFOFMUsers(int lfoNum) const278 std::vector<int> BambooTracker::getLFOFMUsers(int lfoNum) const
279 {
280 	return instMan_->getLFOFMUsers(lfoNum);
281 }
282 
addOperatorSequenceFMSequenceCommand(FMEnvelopeParameter param,int opSeqNum,int type,int data)283 void BambooTracker::addOperatorSequenceFMSequenceCommand(FMEnvelopeParameter param, int opSeqNum, int type, int data)
284 {
285 	instMan_->addOperatorSequenceFMSequenceCommand(param, opSeqNum, type, data);
286 }
287 
removeOperatorSequenceFMSequenceCommand(FMEnvelopeParameter param,int opSeqNum)288 void BambooTracker::removeOperatorSequenceFMSequenceCommand(FMEnvelopeParameter param, int opSeqNum)
289 {
290 	instMan_->removeOperatorSequenceFMSequenceCommand(param, opSeqNum);
291 }
292 
setOperatorSequenceFMSequenceCommand(FMEnvelopeParameter param,int opSeqNum,int cnt,int type,int data)293 void BambooTracker::setOperatorSequenceFMSequenceCommand(FMEnvelopeParameter param, int opSeqNum, int cnt, int type, int data)
294 {
295 	instMan_->setOperatorSequenceFMSequenceCommand(param, opSeqNum, cnt, type, data);
296 }
297 
setOperatorSequenceFMLoops(FMEnvelopeParameter param,int opSeqNum,std::vector<int> begins,std::vector<int> ends,std::vector<int> times)298 void BambooTracker::setOperatorSequenceFMLoops(FMEnvelopeParameter param, int opSeqNum, std::vector<int> begins, std::vector<int> ends, std::vector<int> times)
299 {
300 	instMan_->setOperatorSequenceFMLoops(param, opSeqNum, std::move(begins), std::move(ends), std::move(times));
301 }
302 
setOperatorSequenceFMRelease(FMEnvelopeParameter param,int opSeqNum,ReleaseType type,int begin)303 void BambooTracker::setOperatorSequenceFMRelease(FMEnvelopeParameter param, int opSeqNum, ReleaseType type, int begin)
304 {
305 	instMan_->setOperatorSequenceFMRelease(param, opSeqNum, type, begin);
306 }
307 
setInstrumentFMOperatorSequence(int instNum,FMEnvelopeParameter param,int opSeqNum)308 void BambooTracker::setInstrumentFMOperatorSequence(int instNum, FMEnvelopeParameter param, int opSeqNum)
309 {
310 	instMan_->setInstrumentFMOperatorSequence(instNum, param, opSeqNum);
311 	opnaCtrl_->updateInstrumentFM(instNum);
312 }
313 
setInstrumentFMOperatorSequenceEnabled(int instNum,FMEnvelopeParameter param,bool enabled)314 void BambooTracker::setInstrumentFMOperatorSequenceEnabled(int instNum, FMEnvelopeParameter param, bool enabled)
315 {
316 	instMan_->setInstrumentFMOperatorSequenceEnabled(instNum, param, enabled);
317 	opnaCtrl_->updateInstrumentFM(instNum);
318 }
319 
getOperatorSequenceFMUsers(FMEnvelopeParameter param,int opSeqNum) const320 std::vector<int> BambooTracker::getOperatorSequenceFMUsers(FMEnvelopeParameter param, int opSeqNum) const
321 {
322 	return instMan_->getOperatorSequenceFMUsers(param, opSeqNum);
323 }
324 
setArpeggioFMType(int arpNum,SequenceType type)325 void BambooTracker::setArpeggioFMType(int arpNum, SequenceType type)
326 {
327 	instMan_->setArpeggioFMType(arpNum, type);
328 }
329 
addArpeggioFMSequenceCommand(int arpNum,int type,int data)330 void BambooTracker::addArpeggioFMSequenceCommand(int arpNum, int type, int data)
331 {
332 	instMan_->addArpeggioFMSequenceCommand(arpNum, type, data);
333 }
334 
removeArpeggioFMSequenceCommand(int arpNum)335 void BambooTracker::removeArpeggioFMSequenceCommand(int arpNum)
336 {
337 	instMan_->removeArpeggioFMSequenceCommand(arpNum);
338 }
339 
setArpeggioFMSequenceCommand(int arpNum,int cnt,int type,int data)340 void BambooTracker::setArpeggioFMSequenceCommand(int arpNum, int cnt, int type, int data)
341 {
342 	instMan_->setArpeggioFMSequenceCommand(arpNum, cnt, type, data);
343 }
344 
setArpeggioFMLoops(int arpNum,std::vector<int> begins,std::vector<int> ends,std::vector<int> times)345 void BambooTracker::setArpeggioFMLoops(int arpNum, std::vector<int> begins, std::vector<int> ends, std::vector<int> times)
346 {
347 	instMan_->setArpeggioFMLoops(arpNum, std::move(begins), std::move(ends), std::move(times));
348 }
349 
setArpeggioFMRelease(int arpNum,ReleaseType type,int begin)350 void BambooTracker::setArpeggioFMRelease(int arpNum, ReleaseType type, int begin)
351 {
352 	instMan_->setArpeggioFMRelease(arpNum, type, begin);
353 }
354 
setInstrumentFMArpeggio(int instNum,FMOperatorType op,int arpNum)355 void BambooTracker::setInstrumentFMArpeggio(int instNum, FMOperatorType op, int arpNum)
356 {
357 	instMan_->setInstrumentFMArpeggio(instNum, op, arpNum);
358 	opnaCtrl_->updateInstrumentFM(instNum);
359 }
360 
setInstrumentFMArpeggioEnabled(int instNum,FMOperatorType op,bool enabled)361 void BambooTracker::setInstrumentFMArpeggioEnabled(int instNum, FMOperatorType op, bool enabled)
362 {
363 	instMan_->setInstrumentFMArpeggioEnabled(instNum, op, enabled);
364 	opnaCtrl_->updateInstrumentFM(instNum);
365 }
366 
getArpeggioFMUsers(int arpNum) const367 std::vector<int> BambooTracker::getArpeggioFMUsers(int arpNum) const
368 {
369 	return instMan_->getArpeggioFMUsers(arpNum);
370 }
371 
setPitchFMType(int ptNum,SequenceType type)372 void BambooTracker::setPitchFMType(int ptNum, SequenceType type)
373 {
374 	instMan_->setPitchFMType(ptNum, type);
375 }
376 
addPitchFMSequenceCommand(int ptNum,int type,int data)377 void BambooTracker::addPitchFMSequenceCommand(int ptNum, int type, int data)
378 {
379 	instMan_->addPitchFMSequenceCommand(ptNum, type, data);
380 }
381 
removePitchFMSequenceCommand(int ptNum)382 void BambooTracker::removePitchFMSequenceCommand(int ptNum)
383 {
384 	instMan_->removePitchFMSequenceCommand(ptNum);
385 }
386 
setPitchFMSequenceCommand(int ptNum,int cnt,int type,int data)387 void BambooTracker::setPitchFMSequenceCommand(int ptNum, int cnt, int type, int data)
388 {
389 	instMan_->setPitchFMSequenceCommand(ptNum, cnt, type, data);
390 }
391 
setPitchFMLoops(int ptNum,std::vector<int> begins,std::vector<int> ends,std::vector<int> times)392 void BambooTracker::setPitchFMLoops(int ptNum, std::vector<int> begins, std::vector<int> ends, std::vector<int> times)
393 {
394 	instMan_->setPitchFMLoops(ptNum, std::move(begins), std::move(ends), std::move(times));
395 }
396 
setPitchFMRelease(int ptNum,ReleaseType type,int begin)397 void BambooTracker::setPitchFMRelease(int ptNum, ReleaseType type, int begin)
398 {
399 	instMan_->setPitchFMRelease(ptNum, type, begin);
400 }
401 
setInstrumentFMPitch(int instNum,FMOperatorType op,int ptNum)402 void BambooTracker::setInstrumentFMPitch(int instNum, FMOperatorType op, int ptNum)
403 {
404 	instMan_->setInstrumentFMPitch(instNum, op, ptNum);
405 	opnaCtrl_->updateInstrumentFM(instNum);
406 }
407 
setInstrumentFMPitchEnabled(int instNum,FMOperatorType op,bool enabled)408 void BambooTracker::setInstrumentFMPitchEnabled(int instNum, FMOperatorType op, bool enabled)
409 {
410 	instMan_->setInstrumentFMPitchEnabled(instNum, op, enabled);
411 	opnaCtrl_->updateInstrumentFM(instNum);
412 }
413 
getPitchFMUsers(int ptNum) const414 std::vector<int> BambooTracker::getPitchFMUsers(int ptNum) const
415 {
416 	return instMan_->getPitchFMUsers(ptNum);
417 }
418 
setInstrumentFMEnvelopeResetEnabled(int instNum,FMOperatorType op,bool enabled)419 void BambooTracker::setInstrumentFMEnvelopeResetEnabled(int instNum, FMOperatorType op, bool enabled)
420 {
421 	instMan_->setInstrumentFMEnvelopeResetEnabled(instNum, op, enabled);
422 	opnaCtrl_->updateInstrumentFM(instNum);
423 }
424 
425 //--- SSG
addWaveformSSGSequenceCommand(int wfNum,int type,int data)426 void BambooTracker::addWaveformSSGSequenceCommand(int wfNum, int type, int data)
427 {
428 	instMan_->addWaveformSSGSequenceCommand(wfNum, type, data);
429 }
430 
removeWaveformSSGSequenceCommand(int wfNum)431 void BambooTracker::removeWaveformSSGSequenceCommand(int wfNum)
432 {
433 	instMan_->removeWaveformSSGSequenceCommand(wfNum);
434 }
435 
setWaveformSSGSequenceCommand(int wfNum,int cnt,int type,int data)436 void BambooTracker::setWaveformSSGSequenceCommand(int wfNum, int cnt, int type, int data)
437 {
438 	instMan_->setWaveformSSGSequenceCommand(wfNum, cnt, type, data);
439 }
440 
setWaveformSSGLoops(int wfNum,std::vector<int> begins,std::vector<int> ends,std::vector<int> times)441 void BambooTracker::setWaveformSSGLoops(int wfNum, std::vector<int> begins, std::vector<int> ends, std::vector<int> times)
442 {
443 	instMan_->setWaveformSSGLoops(wfNum, std::move(begins), std::move(ends), std::move(times));
444 }
445 
setWaveformSSGRelease(int wfNum,ReleaseType type,int begin)446 void BambooTracker::setWaveformSSGRelease(int wfNum, ReleaseType type, int begin)
447 {
448 	instMan_->setWaveformSSGRelease(wfNum, type, begin);
449 }
450 
setInstrumentSSGWaveform(int instNum,int wfNum)451 void BambooTracker::setInstrumentSSGWaveform(int instNum, int wfNum)
452 {
453 	instMan_->setInstrumentSSGWaveform(instNum, wfNum);
454 	opnaCtrl_->updateInstrumentSSG(instNum);
455 }
456 
setInstrumentSSGWaveformEnabled(int instNum,bool enabled)457 void BambooTracker::setInstrumentSSGWaveformEnabled(int instNum, bool enabled)
458 {
459 	instMan_->setInstrumentSSGWaveformEnabled(instNum, enabled);
460 	opnaCtrl_->updateInstrumentSSG(instNum);
461 }
462 
getWaveformSSGUsers(int wfNum) const463 std::vector<int> BambooTracker::getWaveformSSGUsers(int wfNum) const
464 {
465 	return instMan_->getWaveformSSGUsers(wfNum);
466 }
467 
addToneNoiseSSGSequenceCommand(int tnNum,int type,int data)468 void BambooTracker::addToneNoiseSSGSequenceCommand(int tnNum, int type, int data)
469 {
470 	instMan_->addToneNoiseSSGSequenceCommand(tnNum, type, data);
471 }
472 
removeToneNoiseSSGSequenceCommand(int tnNum)473 void BambooTracker::removeToneNoiseSSGSequenceCommand(int tnNum)
474 {
475 	instMan_->removeToneNoiseSSGSequenceCommand(tnNum);
476 }
477 
setToneNoiseSSGSequenceCommand(int tnNum,int cnt,int type,int data)478 void BambooTracker::setToneNoiseSSGSequenceCommand(int tnNum, int cnt, int type, int data)
479 {
480 	instMan_->setToneNoiseSSGSequenceCommand(tnNum, cnt, type, data);
481 }
482 
setToneNoiseSSGLoops(int tnNum,std::vector<int> begins,std::vector<int> ends,std::vector<int> times)483 void BambooTracker::setToneNoiseSSGLoops(int tnNum, std::vector<int> begins, std::vector<int> ends, std::vector<int> times)
484 {
485 	instMan_->setToneNoiseSSGLoops(tnNum, std::move(begins), std::move(ends), std::move(times));
486 }
487 
setToneNoiseSSGRelease(int tnNum,ReleaseType type,int begin)488 void BambooTracker::setToneNoiseSSGRelease(int tnNum, ReleaseType type, int begin)
489 {
490 	instMan_->setToneNoiseSSGRelease(tnNum, type, begin);
491 }
492 
setInstrumentSSGToneNoise(int instNum,int tnNum)493 void BambooTracker::setInstrumentSSGToneNoise(int instNum, int tnNum)
494 {
495 	instMan_->setInstrumentSSGToneNoise(instNum, tnNum);
496 	opnaCtrl_->updateInstrumentSSG(instNum);
497 }
498 
setInstrumentSSGToneNoiseEnabled(int instNum,bool enabled)499 void BambooTracker::setInstrumentSSGToneNoiseEnabled(int instNum, bool enabled)
500 {
501 	instMan_->setInstrumentSSGToneNoiseEnabled(instNum, enabled);
502 	opnaCtrl_->updateInstrumentSSG(instNum);
503 }
504 
getToneNoiseSSGUsers(int tnNum) const505 std::vector<int> BambooTracker::getToneNoiseSSGUsers(int tnNum) const
506 {
507 	return instMan_->getToneNoiseSSGUsers(tnNum);
508 }
509 
addEnvelopeSSGSequenceCommand(int envNum,int type,int data)510 void BambooTracker::addEnvelopeSSGSequenceCommand(int envNum, int type, int data)
511 {
512 	instMan_->addEnvelopeSSGSequenceCommand(envNum, type, data);
513 }
514 
removeEnvelopeSSGSequenceCommand(int envNum)515 void BambooTracker::removeEnvelopeSSGSequenceCommand(int envNum)
516 {
517 	instMan_->removeEnvelopeSSGSequenceCommand(envNum);
518 }
519 
setEnvelopeSSGSequenceCommand(int envNum,int cnt,int type,int data)520 void BambooTracker::setEnvelopeSSGSequenceCommand(int envNum, int cnt, int type, int data)
521 {
522 	instMan_->setEnvelopeSSGSequenceCommand(envNum, cnt, type, data);
523 }
524 
setEnvelopeSSGLoops(int envNum,std::vector<int> begins,std::vector<int> ends,std::vector<int> times)525 void BambooTracker::setEnvelopeSSGLoops(int envNum, std::vector<int> begins, std::vector<int> ends, std::vector<int> times)
526 {
527 	instMan_->setEnvelopeSSGLoops(envNum, std::move(begins), std::move(ends), std::move(times));
528 }
529 
setEnvelopeSSGRelease(int envNum,ReleaseType type,int begin)530 void BambooTracker::setEnvelopeSSGRelease(int envNum, ReleaseType type, int begin)
531 {
532 	instMan_->setEnvelopeSSGRelease(envNum, type, begin);
533 }
534 
setInstrumentSSGEnvelope(int instNum,int envNum)535 void BambooTracker::setInstrumentSSGEnvelope(int instNum, int envNum)
536 {
537 	instMan_->setInstrumentSSGEnvelope(instNum, envNum);
538 	opnaCtrl_->updateInstrumentSSG(instNum);
539 }
540 
setInstrumentSSGEnvelopeEnabled(int instNum,bool enabled)541 void BambooTracker::setInstrumentSSGEnvelopeEnabled(int instNum, bool enabled)
542 {
543 	instMan_->setInstrumentSSGEnvelopeEnabled(instNum, enabled);
544 	opnaCtrl_->updateInstrumentSSG(instNum);
545 }
546 
getEnvelopeSSGUsers(int envNum) const547 std::vector<int> BambooTracker::getEnvelopeSSGUsers(int envNum) const
548 {
549 	return instMan_->getEnvelopeSSGUsers(envNum);
550 }
551 
setArpeggioSSGType(int arpNum,SequenceType type)552 void BambooTracker::setArpeggioSSGType(int arpNum, SequenceType type)
553 {
554 	instMan_->setArpeggioSSGType(arpNum, type);
555 }
556 
addArpeggioSSGSequenceCommand(int arpNum,int type,int data)557 void BambooTracker::addArpeggioSSGSequenceCommand(int arpNum, int type, int data)
558 {
559 	instMan_->addArpeggioSSGSequenceCommand(arpNum, type, data);
560 }
561 
removeArpeggioSSGSequenceCommand(int arpNum)562 void BambooTracker::removeArpeggioSSGSequenceCommand(int arpNum)
563 {
564 	instMan_->removeArpeggioSSGSequenceCommand(arpNum);
565 }
566 
setArpeggioSSGSequenceCommand(int arpNum,int cnt,int type,int data)567 void BambooTracker::setArpeggioSSGSequenceCommand(int arpNum, int cnt, int type, int data)
568 {
569 	instMan_->setArpeggioSSGSequenceCommand(arpNum, cnt, type, data);
570 }
571 
setArpeggioSSGLoops(int arpNum,std::vector<int> begins,std::vector<int> ends,std::vector<int> times)572 void BambooTracker::setArpeggioSSGLoops(int arpNum, std::vector<int> begins, std::vector<int> ends, std::vector<int> times)
573 {
574 	instMan_->setArpeggioSSGLoops(arpNum, std::move(begins), std::move(ends), std::move(times));
575 }
576 
setArpeggioSSGRelease(int arpNum,ReleaseType type,int begin)577 void BambooTracker::setArpeggioSSGRelease(int arpNum, ReleaseType type, int begin)
578 {
579 	instMan_->setArpeggioSSGRelease(arpNum, type, begin);
580 }
581 
setInstrumentSSGArpeggio(int instNum,int arpNum)582 void BambooTracker::setInstrumentSSGArpeggio(int instNum, int arpNum)
583 {
584 	instMan_->setInstrumentSSGArpeggio(instNum, arpNum);
585 	opnaCtrl_->updateInstrumentSSG(instNum);
586 }
587 
setInstrumentSSGArpeggioEnabled(int instNum,bool enabled)588 void BambooTracker::setInstrumentSSGArpeggioEnabled(int instNum, bool enabled)
589 {
590 	instMan_->setInstrumentSSGArpeggioEnabled(instNum, enabled);
591 	opnaCtrl_->updateInstrumentSSG(instNum);
592 }
593 
getArpeggioSSGUsers(int arpNum) const594 std::vector<int> BambooTracker::getArpeggioSSGUsers(int arpNum) const
595 {
596 	return instMan_->getArpeggioSSGUsers(arpNum);
597 }
598 
setPitchSSGType(int ptNum,SequenceType type)599 void BambooTracker::setPitchSSGType(int ptNum, SequenceType type)
600 {
601 	instMan_->setPitchSSGType(ptNum, type);
602 }
603 
addPitchSSGSequenceCommand(int ptNum,int type,int data)604 void BambooTracker::addPitchSSGSequenceCommand(int ptNum, int type, int data)
605 {
606 	instMan_->addPitchSSGSequenceCommand(ptNum, type, data);
607 }
608 
removePitchSSGSequenceCommand(int ptNum)609 void BambooTracker::removePitchSSGSequenceCommand(int ptNum)
610 {
611 	instMan_->removePitchSSGSequenceCommand(ptNum);
612 }
613 
setPitchSSGSequenceCommand(int ptNum,int cnt,int type,int data)614 void BambooTracker::setPitchSSGSequenceCommand(int ptNum, int cnt, int type, int data)
615 {
616 	instMan_->setPitchSSGSequenceCommand(ptNum, cnt, type, data);
617 }
618 
setPitchSSGLoops(int ptNum,std::vector<int> begins,std::vector<int> ends,std::vector<int> times)619 void BambooTracker::setPitchSSGLoops(int ptNum, std::vector<int> begins, std::vector<int> ends, std::vector<int> times)
620 {
621 	instMan_->setPitchSSGLoops(ptNum, std::move(begins), std::move(ends), std::move(times));
622 }
623 
setPitchSSGRelease(int ptNum,ReleaseType type,int begin)624 void BambooTracker::setPitchSSGRelease(int ptNum, ReleaseType type, int begin)
625 {
626 	instMan_->setPitchSSGRelease(ptNum, type, begin);
627 }
628 
setInstrumentSSGPitch(int instNum,int ptNum)629 void BambooTracker::setInstrumentSSGPitch(int instNum, int ptNum)
630 {
631 	instMan_->setInstrumentSSGPitch(instNum, ptNum);
632 	opnaCtrl_->updateInstrumentSSG(instNum);
633 }
634 
setInstrumentSSGPitchEnabled(int instNum,bool enabled)635 void BambooTracker::setInstrumentSSGPitchEnabled(int instNum, bool enabled)
636 {
637 	instMan_->setInstrumentSSGPitchEnabled(instNum, enabled);
638 	opnaCtrl_->updateInstrumentSSG(instNum);
639 }
640 
getPitchSSGUsers(int ptNum) const641 std::vector<int> BambooTracker::getPitchSSGUsers(int ptNum) const
642 {
643 	return instMan_->getPitchSSGUsers(ptNum);
644 }
645 
646 //--- ADPCM
getADPCMLimit() const647 size_t BambooTracker::getADPCMLimit() const
648 {
649 	return opnaCtrl_->getDRAMSize();
650 }
651 
652 
getADPCMStoredSize() const653 size_t BambooTracker::getADPCMStoredSize() const
654 {
655 	return opnaCtrl_->getADPCMStoredSize();
656 }
657 
setSampleADPCMRootKeyNumber(int sampNum,int n)658 void BambooTracker::setSampleADPCMRootKeyNumber(int sampNum, int n)
659 {
660 	instMan_->setSampleADPCMRootKeyNumber(sampNum, n);
661 	// opnaCtrl is changed through refInstADPCM (shared_ptr)
662 }
663 
getSampleADPCMRootKeyNumber(int sampNum) const664 int BambooTracker::getSampleADPCMRootKeyNumber(int sampNum) const
665 {
666 	return instMan_->getSampleADPCMRootKeyNumber(sampNum);
667 }
668 
setSampleADPCMRootDeltaN(int sampNum,int dn)669 void BambooTracker::setSampleADPCMRootDeltaN(int sampNum, int dn)
670 {
671 	instMan_->setSampleADPCMRootDeltaN(sampNum, dn);
672 	// opnaCtrl is changed through refInstADPCM (shared_ptr)
673 }
674 
getSampleADPCMRootDeltaN(int sampNum) const675 int BambooTracker::getSampleADPCMRootDeltaN(int sampNum) const
676 {
677 	return instMan_->getSampleADPCMRootDeltaN(sampNum);
678 }
679 
setSampleADPCMRepeatEnabled(int sampNum,bool enabled)680 void BambooTracker::setSampleADPCMRepeatEnabled(int sampNum, bool enabled)
681 {
682 	instMan_->setSampleADPCMRepeatEnabled(sampNum, enabled);
683 	// opnaCtrl is changed through refInstADPCM (shared_ptr)
684 }
685 
getSampleADPCMRepeatEnabled(int sampNum) const686 bool BambooTracker::getSampleADPCMRepeatEnabled(int sampNum) const
687 {
688 	return instMan_->isSampleADPCMRepeatable(sampNum);
689 }
690 
storeSampleADPCMRawSample(int sampNum,std::vector<uint8_t> sample)691 void BambooTracker::storeSampleADPCMRawSample(int sampNum, std::vector<uint8_t> sample)
692 {
693 	instMan_->storeSampleADPCMRawSample(sampNum, sample);
694 }
695 
getSampleADPCMRawSample(int sampNum) const696 std::vector<uint8_t> BambooTracker::getSampleADPCMRawSample(int sampNum) const
697 {
698 	return instMan_->getSampleADPCMRawSample(sampNum);
699 }
700 
clearSampleADPCMRawSample(int sampNum)701 void BambooTracker::clearSampleADPCMRawSample(int sampNum)
702 {
703 	instMan_->clearSampleADPCMRawSample(sampNum);
704 }
705 
assignSampleADPCMRawSamples()706 void BambooTracker::assignSampleADPCMRawSamples()
707 {
708 	opnaCtrl_->clearSamplesADPCM();
709 	std::vector<int> idcs = storeOnlyUsedSamples_ ? instMan_->getSampleADPCMValidIndices()
710 												  : instMan_->getSampleADPCMEntriedIndices();
711 	for (auto sampNum : idcs) {
712 		std::vector<size_t> addresses
713 				= opnaCtrl_->storeSampleADPCM(instMan_->getSampleADPCMRawSample(sampNum));
714 		instMan_->setSampleADPCMStartAddress(sampNum, addresses[0]);
715 		instMan_->setSampleADPCMStopAddress(sampNum, addresses[1]);
716 	}
717 }
718 
getSampleADPCMStartAddress(int sampNum) const719 size_t BambooTracker::getSampleADPCMStartAddress(int sampNum) const
720 {
721 	return instMan_->getSampleADPCMStartAddress(sampNum);
722 }
723 
getSampleADPCMStopAddress(int sampNum) const724 size_t BambooTracker::getSampleADPCMStopAddress(int sampNum) const
725 {
726 	return instMan_->getSampleADPCMStopAddress(sampNum);
727 }
728 
setInstrumentADPCMSample(int instNum,int sampNum)729 void BambooTracker::setInstrumentADPCMSample(int instNum, int sampNum)
730 {
731 	instMan_->setInstrumentADPCMSample(instNum, sampNum);
732 	opnaCtrl_->updateInstrumentADPCM(instNum);
733 }
734 
getSampleADPCMUsers(int sampNum) const735 std::vector<int> BambooTracker::getSampleADPCMUsers(int sampNum) const
736 {
737 	return instMan_->getSampleADPCMUsers(sampNum);
738 }
739 
addEnvelopeADPCMSequenceCommand(int envNum,int type,int data)740 void BambooTracker::addEnvelopeADPCMSequenceCommand(int envNum, int type, int data)
741 {
742 	instMan_->addEnvelopeADPCMSequenceCommand(envNum, type, data);
743 }
744 
removeEnvelopeADPCMSequenceCommand(int envNum)745 void BambooTracker::removeEnvelopeADPCMSequenceCommand(int envNum)
746 {
747 	instMan_->removeEnvelopeADPCMSequenceCommand(envNum);
748 }
749 
setEnvelopeADPCMSequenceCommand(int envNum,int cnt,int type,int data)750 void BambooTracker::setEnvelopeADPCMSequenceCommand(int envNum, int cnt, int type, int data)
751 {
752 	instMan_->setEnvelopeADPCMSequenceCommand(envNum, cnt, type, data);
753 }
754 
setEnvelopeADPCMLoops(int envNum,std::vector<int> begins,std::vector<int> ends,std::vector<int> times)755 void BambooTracker::setEnvelopeADPCMLoops(int envNum, std::vector<int> begins, std::vector<int> ends, std::vector<int> times)
756 {
757 	instMan_->setEnvelopeADPCMLoops(envNum, std::move(begins), std::move(ends), std::move(times));
758 }
759 
setEnvelopeADPCMRelease(int envNum,ReleaseType type,int begin)760 void BambooTracker::setEnvelopeADPCMRelease(int envNum, ReleaseType type, int begin)
761 {
762 	instMan_->setEnvelopeADPCMRelease(envNum, type, begin);
763 }
764 
setInstrumentADPCMEnvelope(int instNum,int envNum)765 void BambooTracker::setInstrumentADPCMEnvelope(int instNum, int envNum)
766 {
767 	instMan_->setInstrumentADPCMEnvelope(instNum, envNum);
768 	opnaCtrl_->updateInstrumentADPCM(instNum);
769 }
770 
setInstrumentADPCMEnvelopeEnabled(int instNum,bool enabled)771 void BambooTracker::setInstrumentADPCMEnvelopeEnabled(int instNum, bool enabled)
772 {
773 	instMan_->setInstrumentADPCMEnvelopeEnabled(instNum, enabled);
774 	opnaCtrl_->updateInstrumentADPCM(instNum);
775 }
776 
getEnvelopeADPCMUsers(int envNum) const777 std::vector<int> BambooTracker::getEnvelopeADPCMUsers(int envNum) const
778 {
779 	return instMan_->getEnvelopeADPCMUsers(envNum);
780 }
781 
setArpeggioADPCMType(int arpNum,SequenceType type)782 void BambooTracker::setArpeggioADPCMType(int arpNum, SequenceType type)
783 {
784 	instMan_->setArpeggioADPCMType(arpNum, type);
785 }
786 
addArpeggioADPCMSequenceCommand(int arpNum,int type,int data)787 void BambooTracker::addArpeggioADPCMSequenceCommand(int arpNum, int type, int data)
788 {
789 	instMan_->addArpeggioADPCMSequenceCommand(arpNum, type, data);
790 }
791 
removeArpeggioADPCMSequenceCommand(int arpNum)792 void BambooTracker::removeArpeggioADPCMSequenceCommand(int arpNum)
793 {
794 	instMan_->removeArpeggioADPCMSequenceCommand(arpNum);
795 }
796 
setArpeggioADPCMSequenceCommand(int arpNum,int cnt,int type,int data)797 void BambooTracker::setArpeggioADPCMSequenceCommand(int arpNum, int cnt, int type, int data)
798 {
799 	instMan_->setArpeggioADPCMSequenceCommand(arpNum, cnt, type, data);
800 }
801 
setArpeggioADPCMLoops(int arpNum,std::vector<int> begins,std::vector<int> ends,std::vector<int> times)802 void BambooTracker::setArpeggioADPCMLoops(int arpNum, std::vector<int> begins, std::vector<int> ends, std::vector<int> times)
803 {
804 	instMan_->setArpeggioADPCMLoops(arpNum, std::move(begins), std::move(ends), std::move(times));
805 }
806 
setArpeggioADPCMRelease(int arpNum,ReleaseType type,int begin)807 void BambooTracker::setArpeggioADPCMRelease(int arpNum, ReleaseType type, int begin)
808 {
809 	instMan_->setArpeggioADPCMRelease(arpNum, type, begin);
810 }
811 
setInstrumentADPCMArpeggio(int instNum,int arpNum)812 void BambooTracker::setInstrumentADPCMArpeggio(int instNum, int arpNum)
813 {
814 	instMan_->setInstrumentADPCMArpeggio(instNum, arpNum);
815 	opnaCtrl_->updateInstrumentADPCM(instNum);
816 }
817 
setInstrumentADPCMArpeggioEnabled(int instNum,bool enabled)818 void BambooTracker::setInstrumentADPCMArpeggioEnabled(int instNum, bool enabled)
819 {
820 	instMan_->setInstrumentADPCMArpeggioEnabled(instNum, enabled);
821 	opnaCtrl_->updateInstrumentADPCM(instNum);
822 }
823 
getArpeggioADPCMUsers(int arpNum) const824 std::vector<int> BambooTracker::getArpeggioADPCMUsers(int arpNum) const
825 {
826 	return instMan_->getArpeggioADPCMUsers(arpNum);
827 }
828 
setPitchADPCMType(int ptNum,SequenceType type)829 void BambooTracker::setPitchADPCMType(int ptNum, SequenceType type)
830 {
831 	instMan_->setPitchADPCMType(ptNum, type);
832 }
833 
addPitchADPCMSequenceCommand(int ptNum,int type,int data)834 void BambooTracker::addPitchADPCMSequenceCommand(int ptNum, int type, int data)
835 {
836 	instMan_->addPitchADPCMSequenceCommand(ptNum, type, data);
837 }
838 
removePitchADPCMSequenceCommand(int ptNum)839 void BambooTracker::removePitchADPCMSequenceCommand(int ptNum)
840 {
841 	instMan_->removePitchADPCMSequenceCommand(ptNum);
842 }
843 
setPitchADPCMSequenceCommand(int ptNum,int cnt,int type,int data)844 void BambooTracker::setPitchADPCMSequenceCommand(int ptNum, int cnt, int type, int data)
845 {
846 	instMan_->setPitchADPCMSequenceCommand(ptNum, cnt, type, data);
847 }
848 
setPitchADPCMLoops(int ptNum,std::vector<int> begins,std::vector<int> ends,std::vector<int> times)849 void BambooTracker::setPitchADPCMLoops(int ptNum, std::vector<int> begins, std::vector<int> ends, std::vector<int> times)
850 {
851 	instMan_->setPitchADPCMLoops(ptNum, std::move(begins), std::move(ends), std::move(times));
852 }
853 
setPitchADPCMRelease(int ptNum,ReleaseType type,int begin)854 void BambooTracker::setPitchADPCMRelease(int ptNum, ReleaseType type, int begin)
855 {
856 	instMan_->setPitchADPCMRelease(ptNum, type, begin);
857 }
858 
setInstrumentADPCMPitch(int instNum,int ptNum)859 void BambooTracker::setInstrumentADPCMPitch(int instNum, int ptNum)
860 {
861 	instMan_->setInstrumentADPCMPitch(instNum, ptNum);
862 	opnaCtrl_->updateInstrumentADPCM(instNum);
863 }
864 
setInstrumentADPCMPitchEnabled(int instNum,bool enabled)865 void BambooTracker::setInstrumentADPCMPitchEnabled(int instNum, bool enabled)
866 {
867 	instMan_->setInstrumentADPCMPitchEnabled(instNum, enabled);
868 	opnaCtrl_->updateInstrumentADPCM(instNum);
869 }
870 
getPitchADPCMUsers(int ptNum) const871 std::vector<int> BambooTracker::getPitchADPCMUsers(int ptNum) const
872 {
873 	return instMan_->getPitchADPCMUsers(ptNum);
874 }
875 
876 //--- Drumkit
setInstrumentDrumkitSample(int instNum,int key,int sampNum)877 void BambooTracker::setInstrumentDrumkitSample(int instNum, int key, int sampNum)
878 {
879 	instMan_->setInstrumentDrumkitSamples(instNum, key, sampNum);
880 	opnaCtrl_->updateInstrumentDrumkit(instNum, key);
881 }
882 
setInstrumentDrumkitSampleEnabled(int instNum,int key,bool enabled)883 void BambooTracker::setInstrumentDrumkitSampleEnabled(int instNum, int key, bool enabled)
884 {
885 	instMan_->setInstrumentDrumkitSamplesEnabled(instNum, key, enabled);
886 	opnaCtrl_->updateInstrumentADPCM(instNum);
887 }
888 
setInstrumentDrumkitPitch(int instNum,int key,int pitch)889 void BambooTracker::setInstrumentDrumkitPitch(int instNum, int key, int pitch)
890 {
891 	instMan_->setInstrumentDrumkitPitch(instNum, key, pitch);
892 	opnaCtrl_->updateInstrumentDrumkit(instNum, key);
893 }
894 
895 /********** Song edit **********/
getCurrentSongNumber() const896 int BambooTracker::getCurrentSongNumber() const
897 {
898 	return curSongNum_;
899 }
900 
setCurrentSongNumber(int num)901 void BambooTracker::setCurrentSongNumber(int num)
902 {
903 	curSongNum_ = num;
904 	curTrackNum_ = 0;
905 	curOrderNum_ = 0;
906 	curStepNum_ = 0;
907 	mkOrder_ = -1;
908 	mkStep_ = -1;
909 
910 	auto& song = mod_->getSong(curSongNum_);
911 	songStyle_ = song.getStyle();
912 
913 	playback_->setSong(mod_, curSongNum_);
914 
915 	/*jamMan_->clear();*/
916 
917 	// Reset
918 	opnaCtrl_->reset();
919 	opnaCtrl_->setMode(songStyle_.type);
920 	tickCounter_->resetCount();
921 	tickCounter_->setTempo(song.getTempo());
922 	tickCounter_->setSpeed(song.getSpeed());
923 	tickCounter_->setGroove(mod_->getGroove(song.getGroove()).getSequence());
924 	tickCounter_->setGrooveTrigger(song.isUsedTempo() ? GrooveTrigger::Invalid
925 													  : GrooveTrigger::ValidByGlobal);
926 
927 	std::unordered_map<SoundSource, int> pairs = {
928 		{ SoundSource::FM, getFMChannelCount(songStyle_.type) },
929 		{ SoundSource::SSG, 3 },
930 		{ SoundSource::RHYTHM, 6 },
931 		{ SoundSource::ADPCM, 1 },
932 	};
933 	for (auto& pair : pairs) {
934 		muteState_[pair.first] = std::vector<bool>(pair.second, false);
935 		for (int i = 0; i < pair.second; ++i) opnaCtrl_->setMuteState(pair.first, i, false);
936 	}
937 }
938 
939 /********** Order edit **********/
getCurrentOrderNumber() const940 int BambooTracker::getCurrentOrderNumber() const
941 {
942 	return curOrderNum_;
943 }
944 
setCurrentOrderNumber(int num)945 void BambooTracker::setCurrentOrderNumber(int num)
946 {
947 	curOrderNum_ = num;
948 }
949 
950 /********** Pattern edit **********/
getCurrentStepNumber() const951 int BambooTracker::getCurrentStepNumber() const
952 {
953 	return curStepNum_;
954 }
955 
setCurrentStepNumber(int num)956 void BambooTracker::setCurrentStepNumber(int num)
957 {
958 	curStepNum_ = num;
959 }
960 
961 /********** Undo-Redo **********/
undo()962 void BambooTracker::undo()
963 {
964 	comMan_.undo();
965 }
966 
redo()967 void BambooTracker::redo()
968 {
969 	comMan_.redo();
970 }
971 
clearCommandHistory()972 void BambooTracker::clearCommandHistory()
973 {
974 	comMan_.clear();
975 }
976 
977 /********** Jam mode **********/
toggleJamMode()978 void BambooTracker::toggleJamMode()
979 {
980 	if (jamMan_->toggleJamMode() && !isPlaySong()) {
981 		jamMan_->polyphonic(true);
982 	}
983 	else {
984 		jamMan_->polyphonic(false);
985 	}
986 }
987 
isJamMode() const988 bool BambooTracker::isJamMode() const
989 {
990 	return jamMan_->isJamMode();
991 }
992 
jamKeyOn(JamKey key,bool volumeSet)993 void BambooTracker::jamKeyOn(JamKey key, bool volumeSet)
994 {
995 	int keyNum = octaveAndNoteToNoteNumber(curOctave_, JamManager::jamKeyToNote(key));
996 	const TrackAttribute& attrib = songStyle_.trackAttribs[static_cast<size_t>(curTrackNum_)];
997 	funcJamKeyOn(key, keyNum, attrib, volumeSet);
998 }
999 
jamKeyOn(int keyNum,bool volumeSet)1000 void BambooTracker::jamKeyOn(int keyNum, bool volumeSet)
1001 {
1002 	const TrackAttribute& attrib = songStyle_.trackAttribs[static_cast<size_t>(curTrackNum_)];
1003 	funcJamKeyOn(JamKey::MidiKey, keyNum, attrib, volumeSet);
1004 }
1005 
jamKeyOnForced(JamKey key,SoundSource src,bool volumeSet,std::shared_ptr<AbstractInstrument> inst)1006 void BambooTracker::jamKeyOnForced(JamKey key, SoundSource src, bool volumeSet, std::shared_ptr<AbstractInstrument> inst)
1007 {
1008 	int keyNum = octaveAndNoteToNoteNumber(curOctave_, JamManager::jamKeyToNote(key));
1009 	auto it = std::find_if(songStyle_.trackAttribs.begin(), songStyle_.trackAttribs.end(),
1010 						   [src](TrackAttribute& attrib) { return attrib.source == src; });
1011 	funcJamKeyOn(key, keyNum, *it, volumeSet, inst);
1012 }
1013 
jamKeyOnForced(int keyNum,SoundSource src,bool volumeSet,std::shared_ptr<AbstractInstrument> inst)1014 void BambooTracker::jamKeyOnForced(int keyNum, SoundSource src, bool volumeSet, std::shared_ptr<AbstractInstrument> inst)
1015 {
1016 	auto it = std::find_if(songStyle_.trackAttribs.begin(), songStyle_.trackAttribs.end(),
1017 						   [src](TrackAttribute& attrib) { return attrib.source == src; });
1018 	funcJamKeyOn(JamKey::MidiKey, keyNum, *it, volumeSet, inst);
1019 }
1020 
funcJamKeyOn(JamKey key,int keyNum,const TrackAttribute & attrib,bool volumeSet,std::shared_ptr<AbstractInstrument> inst)1021 void BambooTracker::funcJamKeyOn(JamKey key, int keyNum, const TrackAttribute& attrib, bool volumeSet,
1022 								 std::shared_ptr<AbstractInstrument> inst)
1023 {
1024 	if (playback_->isPlayingStep()) playback_->stopPlaySong();	// Reset
1025 
1026 	if (attrib.source == SoundSource::RHYTHM) {
1027 		if (volumeSet)
1028 			opnaCtrl_->setVolumeRhythm(attrib.channelInSource, std::min(curVolume_, 0x1f));
1029 		opnaCtrl_->setKeyOnFlagRhythm(attrib.channelInSource);
1030 		opnaCtrl_->updateRegisterStates();
1031 	}
1032 	else {
1033 		std::vector<JamKeyData>&& list = jamMan_->keyOn(key, attrib.channelInSource, attrib.source, keyNum);
1034 		if (list.size() == 2) {	// Key off
1035 			JamKeyData& offData = list[1];
1036 			switch (offData.source) {
1037 			case SoundSource::FM:
1038 				if (songStyle_.type == SongType::FM3chExpanded && offData.channelInSource == 2) {
1039 					opnaCtrl_->keyOffFM(2, true);
1040 					opnaCtrl_->keyOffFM(6, true);
1041 					opnaCtrl_->keyOffFM(7, true);
1042 					opnaCtrl_->keyOffFM(8, true);
1043 				}
1044 				else {
1045 					opnaCtrl_->keyOffFM(offData.channelInSource, true);
1046 				}
1047 				break;
1048 			case SoundSource::SSG:
1049 				opnaCtrl_->keyOffSSG(offData.channelInSource, true);
1050 				break;
1051 			case SoundSource::ADPCM:
1052 				opnaCtrl_->keyOffADPCM(true);
1053 				break;
1054 			default:
1055 				break;
1056 			}
1057 		}
1058 
1059 		if (!inst) {	// Use current instrument if not specified
1060 			inst = instMan_->getInstrumentSharedPtr(curInstNum_);
1061 		}
1062 		JamKeyData& onData = list.front();
1063 
1064 		Note note;
1065 		int octave, pitch;
1066 		if (key == JamKey::MidiKey) {
1067 			auto octNote = noteNumberToOctaveAndNote(onData.keyNum);
1068 			note = octNote.second;
1069 			octave = octNote.first;
1070 		}
1071 		else {
1072 			note = JamManager::jamKeyToNote(onData.key);
1073 			octave = JamManager::calcOctave(curOctave_, onData.key);
1074 			if (octave > 7) {	// Tone range check
1075 				octave = 7;
1076 				note = Note::B;
1077 			}
1078 		}
1079 		pitch = 0;
1080 
1081 		switch (onData.source) {
1082 		case SoundSource::FM:
1083 			if (auto fm = std::dynamic_pointer_cast<InstrumentFM>(inst))
1084 				opnaCtrl_->setInstrumentFM(onData.channelInSource, fm);
1085 			if (volumeSet) {
1086 				int vol;
1087 				if (volFMReversed_) vol = (curVolume_ < 0x80) ? (0x7f - curVolume_) : 0;
1088 				else vol = std::min(curVolume_, 0x7f);
1089 				opnaCtrl_->setVolumeFM(onData.channelInSource, vol);
1090 			}
1091 			if (songStyle_.type == SongType::FM3chExpanded && onData.channelInSource == 2) {
1092 				opnaCtrl_->keyOnFM(2, note, octave, pitch, true);
1093 				opnaCtrl_->keyOnFM(6, note, octave, pitch, true);
1094 				opnaCtrl_->keyOnFM(7, note, octave, pitch, true);
1095 				opnaCtrl_->keyOnFM(8, note, octave, pitch, true);
1096 			}
1097 			else {
1098 				opnaCtrl_->keyOnFM(onData.channelInSource, note, octave, pitch, true);
1099 			}
1100 			break;
1101 		case SoundSource::SSG:
1102 			if (auto ssg = std::dynamic_pointer_cast<InstrumentSSG>(inst))
1103 				opnaCtrl_->setInstrumentSSG(onData.channelInSource, ssg);
1104 			if (volumeSet)
1105 				opnaCtrl_->setVolumeSSG(onData.channelInSource, std::min(curVolume_, 0xf));
1106 			opnaCtrl_->keyOnSSG(onData.channelInSource, note, octave, pitch, true);
1107 			break;
1108 		case SoundSource::ADPCM:
1109 			if (auto adpcm = std::dynamic_pointer_cast<InstrumentADPCM>(inst))
1110 				opnaCtrl_->setInstrumentADPCM(adpcm);
1111 			else if (auto kit = std::dynamic_pointer_cast<InstrumentDrumkit>(inst))
1112 				opnaCtrl_->setInstrumentDrumkit(kit);
1113 			if (volumeSet) opnaCtrl_->setVolumeADPCM(curVolume_);
1114 			opnaCtrl_->keyOnADPCM(note, octave, pitch, true);
1115 			break;
1116 		default:
1117 			break;
1118 		}
1119 	}
1120 }
1121 
jamKeyOff(JamKey key)1122 void BambooTracker::jamKeyOff(JamKey key)
1123 {
1124 	int keyNum = octaveAndNoteToNoteNumber(curOctave_, JamManager::jamKeyToNote(key));
1125 	const TrackAttribute& attrib = songStyle_.trackAttribs[static_cast<size_t>(curTrackNum_)];
1126 	funcJamKeyOff(key, keyNum, attrib);
1127 }
1128 
jamKeyOff(int keyNum)1129 void BambooTracker::jamKeyOff(int keyNum)
1130 {
1131 	const TrackAttribute& attrib = songStyle_.trackAttribs[static_cast<size_t>(curTrackNum_)];
1132 	funcJamKeyOff(JamKey::MidiKey, keyNum, attrib);
1133 }
1134 
jamKeyOffForced(JamKey key,SoundSource src)1135 void BambooTracker::jamKeyOffForced(JamKey key, SoundSource src)
1136 {
1137 	int keyNum = octaveAndNoteToNoteNumber(curOctave_, JamManager::jamKeyToNote(key));
1138 	auto it = std::find_if(songStyle_.trackAttribs.begin(), songStyle_.trackAttribs.end(),
1139 						   [src](TrackAttribute& attrib) { return attrib.source == src; });
1140 	funcJamKeyOff(key, keyNum, *it);
1141 }
1142 
jamKeyOffForced(int keyNum,SoundSource src)1143 void BambooTracker::jamKeyOffForced(int keyNum, SoundSource src)
1144 {
1145 	auto it = std::find_if(songStyle_.trackAttribs.begin(), songStyle_.trackAttribs.end(),
1146 						   [src](TrackAttribute& attrib) { return attrib.source == src; });
1147 	funcJamKeyOff(JamKey::MidiKey, keyNum, *it);
1148 }
1149 
funcJamKeyOff(JamKey key,int keyNum,const TrackAttribute & attrib)1150 void BambooTracker::funcJamKeyOff(JamKey key, int keyNum, const TrackAttribute& attrib)
1151 {
1152 	if (attrib.source == SoundSource::RHYTHM) {
1153 		opnaCtrl_->setKeyOffFlagRhythm(attrib.channelInSource);
1154 		opnaCtrl_->updateRegisterStates();
1155 	}
1156 	else {
1157 		JamKeyData&& data = jamMan_->keyOff(key, keyNum);
1158 
1159 		if (data.channelInSource > -1) {	// Key still sound
1160 			switch (data.source) {
1161 			case SoundSource::FM:
1162 				if (songStyle_.type == SongType::FM3chExpanded && data.channelInSource == 2) {
1163 					opnaCtrl_->keyOffFM(2, true);
1164 					opnaCtrl_->keyOffFM(6, true);
1165 					opnaCtrl_->keyOffFM(7, true);
1166 					opnaCtrl_->keyOffFM(8, true);
1167 				}
1168 				else {
1169 					opnaCtrl_->keyOffFM(data.channelInSource, true);
1170 				}
1171 				break;
1172 			case SoundSource::SSG:
1173 				opnaCtrl_->keyOffSSG(data.channelInSource, true);
1174 				break;
1175 			case SoundSource::ADPCM:
1176 				opnaCtrl_->keyOffADPCM(true);
1177 				break;
1178 			default:
1179 				break;
1180 			}
1181 		}
1182 	}
1183 }
1184 
assignADPCMBeforeForcedJamKeyOn(std::shared_ptr<AbstractInstrument> inst)1185 std::vector<std::vector<size_t>> BambooTracker::assignADPCMBeforeForcedJamKeyOn(std::shared_ptr<AbstractInstrument> inst)
1186 {
1187 	switch (inst->getType()) {
1188 	case InstrumentType::ADPCM:
1189 	{
1190 		opnaCtrl_->clearSamplesADPCM();
1191 		return { opnaCtrl_->storeSampleADPCM(
1192 						std::dynamic_pointer_cast<InstrumentADPCM>(inst)->getRawSample()) };
1193 	}
1194 	case InstrumentType::Drumkit:
1195 	{
1196 		opnaCtrl_->clearSamplesADPCM();
1197 		std::vector<std::vector<size_t>> addrs;
1198 		auto kit = std::dynamic_pointer_cast<InstrumentDrumkit>(inst);
1199 		for (const int& key : kit->getAssignedKeys()) {
1200 			int samp = kit->getSampleNumber(key);
1201 			if (addrs.size() <= static_cast<size_t>(samp)) addrs.resize(samp + 1);
1202 			if (addrs[samp].empty()) addrs[samp] = opnaCtrl_->storeSampleADPCM(kit->getRawSample(key));
1203 		}
1204 		return addrs;
1205 	}
1206 	default:
1207 		return {};
1208 	}
1209 }
1210 
1211 /********** Play song **********/
startPlaySong()1212 void BambooTracker::startPlaySong()
1213 {
1214 	playback_->startPlaySong(curOrderNum_);
1215 	startPlay();
1216 
1217 	if (isFollowPlay_) curStepNum_ = 0;
1218 }
1219 
startPlayFromStart()1220 void BambooTracker::startPlayFromStart()
1221 {
1222 	playback_->startPlayFromStart();
1223 	startPlay();
1224 
1225 	if (isFollowPlay_) {
1226 		curOrderNum_ = 0;
1227 		curStepNum_ = 0;
1228 	}
1229 }
1230 
startPlayPattern()1231 void BambooTracker::startPlayPattern()
1232 {
1233 	playback_->startPlayPattern(curOrderNum_);
1234 	startPlay();
1235 
1236 	if (isFollowPlay_) curStepNum_ = 0;
1237 }
1238 
startPlayFromCurrentStep()1239 void BambooTracker::startPlayFromCurrentStep()
1240 {
1241 	playback_->startPlayFromPosition(curOrderNum_, curStepNum_);
1242 	startPlay();
1243 }
1244 
startPlayFromMarker()1245 bool BambooTracker::startPlayFromMarker()
1246 {
1247 	Song& song = mod_->getSong(curSongNum_);
1248 	if (mkOrder_ != -1 && mkOrder_ < static_cast<int>(song.getOrderSize())
1249 			&& mkStep_ != -1 && mkStep_ < static_cast<int>(song.getPatternSizeFromOrderNumber(mkOrder_))) {
1250 		playback_->startPlayFromPosition(mkOrder_, mkStep_);
1251 		startPlay();
1252 		return true;
1253 	}
1254 	return false;
1255 }
1256 
playStep()1257 void BambooTracker::playStep()
1258 {
1259 	playback_->playStep(curOrderNum_, curStepNum_);
1260 	for (auto& pair : muteState_) {
1261 		for (size_t i = 0; i < pair.second.size(); ++i) {
1262 			opnaCtrl_->setMuteState(pair.first, static_cast<int>(i), pair.second[i]);
1263 		}
1264 	}
1265 }
1266 
startPlay()1267 void BambooTracker::startPlay()
1268 {
1269 	jamMan_->polyphonic(false);
1270 
1271 	for (auto& pair : muteState_) {
1272 		for (size_t i = 0; i < pair.second.size(); ++i) {
1273 			opnaCtrl_->setMuteState(pair.first, static_cast<int>(i), pair.second[i]);
1274 		}
1275 	}
1276 }
1277 
stopPlaySong()1278 void BambooTracker::stopPlaySong()
1279 {
1280 	playback_->stopPlaySong();
1281 	jamMan_->polyphonic(true);
1282 
1283 	for (auto& pair : muteState_) {
1284 		for (size_t i = 0; i < pair.second.size(); ++i) {
1285 			opnaCtrl_->setMuteState(pair.first, static_cast<int>(i), false);
1286 		}
1287 	}
1288 }
1289 
isPlaySong() const1290 bool BambooTracker::isPlaySong() const
1291 {
1292 	return playback_->isPlaySong();
1293 }
1294 
setTrackMuteState(int trackNum,bool isMute)1295 void BambooTracker::setTrackMuteState(int trackNum, bool isMute)
1296 {
1297 	auto& ta = songStyle_.trackAttribs[static_cast<size_t>(trackNum)];
1298 	muteState_.at(ta.source).at(static_cast<size_t>(ta.channelInSource)) = isMute;
1299 	if (isPlaySong()) opnaCtrl_->setMuteState(ta.source, ta.channelInSource, isMute);
1300 }
1301 
isMute(int trackNum)1302 bool BambooTracker::isMute(int trackNum)
1303 {
1304 	auto& ta = songStyle_.trackAttribs[static_cast<size_t>(trackNum)];
1305 	return muteState_.at(ta.source).at(ta.channelInSource);
1306 }
1307 
setFollowPlay(bool isFollowed)1308 void BambooTracker::setFollowPlay(bool isFollowed)
1309 {
1310 	isFollowPlay_ = isFollowed;
1311 	if (isFollowed) {
1312 		int odr = playback_->getPlayingOrderNumber();
1313 		if (odr >= 0) {
1314 			curOrderNum_ = odr;
1315 			curStepNum_ = playback_->getPlayingStepNumber();
1316 		}
1317 	}
1318 }
1319 
isFollowPlay() const1320 bool BambooTracker::isFollowPlay() const
1321 {
1322 	return isFollowPlay_;
1323 }
1324 
getPlayingOrderNumber() const1325 int BambooTracker::getPlayingOrderNumber() const
1326 {
1327 	return playback_->getPlayingOrderNumber();
1328 }
1329 
getPlayingStepNumber() const1330 int BambooTracker::getPlayingStepNumber() const
1331 {
1332 	return playback_->getPlayingStepNumber();
1333 }
1334 
setMarker(int order,int step)1335 void BambooTracker::setMarker(int order, int step)
1336 {
1337 	if (mkOrder_ == order && mkStep_ == step) {
1338 		mkOrder_ = -1;
1339 		mkStep_ = -1;
1340 	}
1341 	else {
1342 		mkOrder_ = order;
1343 		mkStep_ = step;
1344 	}
1345 }
1346 
getMarkerOrder() const1347 int BambooTracker::getMarkerOrder() const
1348 {
1349 	return mkOrder_;
1350 }
1351 
getMarkerStep() const1352 int BambooTracker::getMarkerStep() const
1353 {
1354 	return mkStep_;
1355 }
1356 
1357 /********** Export **********/
exportToWav(WavContainer & container,int loopCnt,std::function<bool ()> bar)1358 bool BambooTracker::exportToWav(WavContainer& container, int loopCnt, std::function<bool()> bar)
1359 {
1360 	int tmpRate = opnaCtrl_->getRate();
1361 	opnaCtrl_->setRate(static_cast<int>(container.getSampleRate()));
1362 	size_t sampCnt = static_cast<size_t>(opnaCtrl_->getRate() * opnaCtrl_->getDuration() / 1000);
1363 	size_t intrCnt = static_cast<size_t>(opnaCtrl_->getRate()) / mod_->getTickFrequency();
1364 	size_t intrCntRest = 0;
1365 	std::vector<int16_t> dumbuf(sampCnt << 1);
1366 
1367 	int endOrder = 0;
1368 	int endStep = 0;
1369 	size_t dummy = 0;
1370 	checkNextPositionOfLastStepAndStepSize(curSongNum_, endOrder, endStep, dummy, dummy);
1371 	bool endFlag = false;
1372 	bool tmpFollow = std::exchange(isFollowPlay_, false);
1373 	std::shared_ptr<chip::WavExportContainer> exCntr = std::make_shared<chip::WavExportContainer>();
1374 	opnaCtrl_->setExportContainer(exCntr);
1375 	startPlayFromStart();
1376 
1377 	while (true) {
1378 		size_t sampCntRest = sampCnt;
1379 		while (sampCntRest) {
1380 			if (!intrCntRest) {	// Interruption
1381 				intrCntRest = intrCnt;    // Set counts to next interruption
1382 
1383 				if (!streamCountUp()) {
1384 					if (bar()) {	// Update lambda function
1385 						stopPlaySong();
1386 						isFollowPlay_ = tmpFollow;
1387 						return false;
1388 					}
1389 
1390 					int playOrder = playback_->getPlayingOrderNumber();
1391 					int playStep = playback_->getPlayingStepNumber();
1392 					if ((playOrder == -1 && playStep == -1)
1393 							|| (playOrder == endOrder && playStep == endStep && !(loopCnt--))){
1394 						endFlag = true;
1395 						break;
1396 					}
1397 				}
1398 			}
1399 
1400 			size_t count = std::min(intrCntRest, sampCntRest);
1401 			sampCntRest -= count;
1402 			intrCntRest -= count;
1403 
1404 			opnaCtrl_->getStreamSamples(&dumbuf[0], count);
1405 		}
1406 
1407 		if (endFlag) break;
1408 	}
1409 
1410 	opnaCtrl_->setExportContainer();
1411 	stopPlaySong();
1412 	isFollowPlay_ = tmpFollow;
1413 	opnaCtrl_->setRate(tmpRate);
1414 
1415 	container.storeSample(exCntr->getStream());
1416 
1417 	return true;
1418 }
1419 
exportToVgm(BinaryContainer & container,int target,bool gd3TagEnabled,GD3Tag tag,std::function<bool ()> bar)1420 bool BambooTracker::exportToVgm(BinaryContainer& container, int target, bool gd3TagEnabled,
1421 								GD3Tag tag, std::function<bool()> bar)
1422 {
1423 	int tmpRate = opnaCtrl_->getRate();
1424 	opnaCtrl_->setRate(44100);
1425 	double dblIntrCnt = 44100.0 / static_cast<double>(mod_->getTickFrequency());
1426 	size_t intrCnt = static_cast<size_t>(dblIntrCnt);
1427 	double intrCntDiff = dblIntrCnt - intrCnt;
1428 	double intrCntRest = 0;
1429 	std::vector<int16_t> dumbuf((intrCnt + 1) << 1);
1430 
1431 	int loopOrder = 0;
1432 	int loopStep = 0;
1433 	size_t dummy = 0;
1434 	checkNextPositionOfLastStepAndStepSize(curSongNum_, loopOrder, loopStep, dummy, dummy);
1435 	bool loopFlag = (loopOrder != -1);
1436 	int endCnt = (loopOrder == -1) ? 0 : 1;
1437 	bool tmpFollow = std::exchange(isFollowPlay_, false);
1438 	uint32_t loopPoint = 0;
1439 	uint32_t loopPointSamples = 0;
1440 
1441 	std::shared_ptr<chip::VgmExportContainer> exCntr
1442 			= std::make_shared<chip::VgmExportContainer>(target, mod_->getTickFrequency());
1443 
1444 	// Set ADPCM
1445 	opnaCtrl_->clearSamplesADPCM();
1446 	std::vector<uint8_t> rom;
1447 	for (auto sampNum : instMan_->getSampleADPCMValidIndices()) {
1448 		std::vector<uint8_t> sample = instMan_->getSampleADPCMRawSample(sampNum);
1449 		std::vector<size_t> addresses = opnaCtrl_->storeSampleADPCM(sample);
1450 		instMan_->setSampleADPCMStartAddress(sampNum, addresses[0]);
1451 		instMan_->setSampleADPCMStopAddress(sampNum, addresses[1]);
1452 
1453 		rom.resize((addresses[1] + 1) << 5);
1454 		std::copy(sample.begin(), sample.end(), rom.begin() + static_cast<int>(addresses[0] << 5));
1455 	}
1456 	exCntr->setDataBlock(std::move(rom));
1457 
1458 	opnaCtrl_->setExportContainer(exCntr);
1459 	startPlayFromStart();
1460 	exCntr->forceMoveLoopPoint();
1461 
1462 	while (true) {
1463 		if (!streamCountUp()) {
1464 			if (bar()) {	// Update lambda function
1465 				stopPlaySong();
1466 				isFollowPlay_ = tmpFollow;
1467 				return false;
1468 			}
1469 
1470 			int playOrder = playback_->getPlayingOrderNumber();
1471 			int playStep = playback_->getPlayingStepNumber();
1472 			if (playOrder == loopOrder && playStep == loopStep && !(endCnt--)) break;
1473 
1474 			if (loopFlag && loopOrder == playOrder && loopStep == playStep) {
1475 				loopPoint = exCntr->setLoopPoint();
1476 				loopPointSamples = exCntr->getSampleLength();
1477 			}
1478 		}
1479 
1480 		intrCntRest += intrCntDiff;
1481 		size_t extraIntrCnt = static_cast<size_t>(intrCntRest);
1482 		intrCntRest -= extraIntrCnt;
1483 		opnaCtrl_->getStreamSamples(&dumbuf[0], intrCnt + extraIntrCnt);
1484 	}
1485 
1486 	opnaCtrl_->setExportContainer();
1487 	stopPlaySong();
1488 	isFollowPlay_ = tmpFollow;
1489 	opnaCtrl_->setRate(tmpRate);
1490 
1491 	try {
1492 		ExportHandler::writeVgm(container, target, exCntr->getData(), CHIP_CLOCK, mod_->getTickFrequency(),
1493 								loopFlag, loopPoint, exCntr->getSampleLength() - loopPointSamples,
1494 								exCntr->getSampleLength(), gd3TagEnabled, tag);
1495 		return true;
1496 	} catch (...) {
1497 		throw;
1498 	}
1499 }
1500 
exportToS98(BinaryContainer & container,int target,bool tagEnabled,S98Tag tag,int rate,std::function<bool ()> bar)1501 bool BambooTracker::exportToS98(BinaryContainer& container, int target, bool tagEnabled,
1502 								S98Tag tag, int rate, std::function<bool()> bar)
1503 {
1504 	int tmpRate = opnaCtrl_->getRate();
1505 	opnaCtrl_->setRate(rate);
1506 	double dblIntrCnt = static_cast<double>(rate) / static_cast<double>(mod_->getTickFrequency());
1507 	size_t intrCnt = static_cast<size_t>(dblIntrCnt);
1508 	double intrCntDiff = dblIntrCnt - intrCnt;
1509 	double intrCntRest = 0;
1510 	std::vector<int16_t> dumbuf((intrCnt + 1) << 1);
1511 
1512 	int loopOrder = 0;
1513 	int loopStep = 0;
1514 	size_t dummy = 0;
1515 	checkNextPositionOfLastStepAndStepSize(curSongNum_, loopOrder, loopStep, dummy, dummy);
1516 	bool loopFlag = (loopOrder != -1);
1517 	int endCnt = (loopOrder == -1) ? 0 : 1;
1518 	bool tmpFollow = std::exchange(isFollowPlay_, false);
1519 	uint32_t loopPoint = 0;
1520 	std::shared_ptr<chip::S98ExportContainer> exCntr = std::make_shared<chip::S98ExportContainer>(target);
1521 	opnaCtrl_->setExportContainer(exCntr);
1522 	startPlayFromStart();
1523 	assignSampleADPCMRawSamples();
1524 	exCntr->forceMoveLoopPoint();
1525 
1526 	while (true) {
1527 		exCntr->getData();	// Set wait counts
1528 		if (!streamCountUp()) {
1529 			if (bar()) {	// Update lambda function
1530 				stopPlaySong();
1531 				isFollowPlay_ = tmpFollow;
1532 				return false;
1533 			}
1534 
1535 			int playOrder = playback_->getPlayingOrderNumber();
1536 			int playStep = playback_->getPlayingStepNumber();
1537 			if (playOrder == loopOrder && playStep == loopStep && !(endCnt--)) break;
1538 
1539 			if (loopFlag && loopOrder == playOrder && loopStep == playStep) {
1540 				loopPoint = exCntr->setLoopPoint();
1541 			}
1542 		}
1543 
1544 		intrCntRest += intrCntDiff;
1545 		size_t extraIntrCnt = static_cast<size_t>(intrCntRest);
1546 		intrCntRest -= extraIntrCnt;
1547 		opnaCtrl_->getStreamSamples(&dumbuf[0], intrCnt + extraIntrCnt);
1548 	}
1549 
1550 	opnaCtrl_->setExportContainer();
1551 	stopPlaySong();
1552 	isFollowPlay_ = tmpFollow;
1553 	opnaCtrl_->setRate(tmpRate);
1554 
1555 	try {
1556 		ExportHandler::writeS98(container, target, exCntr->getData(), CHIP_CLOCK, static_cast<uint32_t>(rate),
1557 								loopFlag, loopPoint, tagEnabled, tag);
1558 		return true;
1559 	} catch (...) {
1560 		throw;
1561 	}
1562 }
1563 
checkNextPositionOfLastStepAndStepSize(int songNum,int & endOrder,int & endStep,size_t & nIntroStep,size_t & nLoopStep) const1564 void BambooTracker::checkNextPositionOfLastStepAndStepSize(int songNum, int& endOrder, int& endStep, size_t& nIntroStep, size_t& nLoopStep) const
1565 {
1566 	Song& song = mod_->getSong(songNum);
1567 	endOrder = 0;
1568 	endStep = 0;
1569 
1570 	int lastOrder = static_cast<int>(song.getOrderSize()) - 1;
1571 	std::unordered_map<int, int> orderStepMap;
1572 	int orderN = 0;
1573 	size_t stepCnt = 0;
1574 	do {
1575 		endOrder = (endOrder + 1) % (lastOrder + 1);
1576 		endStep = 0;
1577 
1578 		int stepN = static_cast<int>(getPatternSizeFromOrderNumber(songNum, orderN)) - 1;
1579 		for (auto attrib : songStyle_.trackAttribs) {
1580 			Step& step = song.getTrack(attrib.number).getPatternFromOrderNumber(orderN).getStep(stepN);
1581 			for (int i = 0; i < 4; ++i) {
1582 				Effect&& eff = Effect::makeEffectData(attrib.source, step.getEffectID(i), step.getEffectValue(i));
1583 				switch (eff.type) {
1584 				case EffectType::PositionJump:
1585 					if (eff.value <= lastOrder) {
1586 						endOrder = eff.value;
1587 						endStep = 0;
1588 					}
1589 					break;
1590 				case EffectType::SongEnd:
1591 					endOrder = -1;
1592 					endStep = -1;
1593 					break;
1594 				case EffectType::PatternBreak:
1595 					if (orderN == lastOrder
1596 							&& eff.value < static_cast<int>(getPatternSizeFromOrderNumber(songNum, 0))) {
1597 						endOrder = 0;
1598 						endStep = eff.value;
1599 					}
1600 					else if (eff.value < static_cast<int>(getPatternSizeFromOrderNumber(songNum, orderN + 1))) {
1601 						endOrder = orderN + 1;
1602 						endStep = eff.value;
1603 					}
1604 					break;
1605 				default:
1606 					break;
1607 				}
1608 			}
1609 		}
1610 
1611 		orderStepMap[orderN] = stepCnt;
1612 		stepCnt += song.getPatternSizeFromOrderNumber(orderN);
1613 		orderN = endOrder;
1614 	} while (orderN != -1 && !orderStepMap.count(orderN));	// stopped song or jumped to played order
1615 
1616 	if (orderN == -1) {
1617 		nIntroStep = stepCnt;
1618 		nLoopStep = 0;
1619 	}
1620 	else {
1621 		nIntroStep = orderStepMap[orderN];
1622 		nLoopStep = stepCnt - orderStepMap[orderN];
1623 	}
1624 }
1625 
1626 /********** Real chip interface **********/
useSCCI(scci::SoundInterfaceManager * manager)1627 void BambooTracker::useSCCI(scci::SoundInterfaceManager* manager)
1628 {
1629 	opnaCtrl_->useSCCI(manager);
1630 }
1631 
useC86CTL(C86ctlBase * base)1632 void BambooTracker::useC86CTL(C86ctlBase* base)
1633 {
1634 	opnaCtrl_->useC86CTL(base);
1635 }
1636 
getRealChipinterface() const1637 RealChipInterface BambooTracker::getRealChipinterface() const
1638 {
1639 	if (opnaCtrl_->isUsedSCCI()) return RealChipInterface::SCCI;
1640 	else if (opnaCtrl_->isUsedC86CTL()) return RealChipInterface::C86CTL;
1641 	else return RealChipInterface::NONE;
1642 }
1643 
1644 /********** Stream events **********/
streamCountUp()1645 int BambooTracker::streamCountUp()
1646 {
1647 	int state = playback_->streamCountUp();
1648 	if (!state && isFollowPlay_ && !playback_->isPlayingStep()) {	// Step
1649 		int odr = playback_->getPlayingOrderNumber();
1650 		if (odr >= 0) {
1651 			curOrderNum_ = odr;
1652 			curStepNum_ = playback_->getPlayingStepNumber();
1653 		}
1654 	}
1655 	return state;
1656 }
1657 
getStreamSamples(int16_t * container,size_t nSamples)1658 void BambooTracker::getStreamSamples(int16_t *container, size_t nSamples)
1659 {
1660 	opnaCtrl_->getStreamSamples(container, nSamples);
1661 }
1662 
killSound()1663 void BambooTracker::killSound()
1664 {
1665 	jamMan_->clear();
1666 	opnaCtrl_->reset();
1667 }
1668 
1669 /********** Stream details **********/
getStreamRate() const1670 int BambooTracker::getStreamRate() const
1671 {
1672 	return opnaCtrl_->getRate();
1673 }
1674 
setStreamRate(int rate)1675 void BambooTracker::setStreamRate(int rate)
1676 {
1677 	opnaCtrl_->setRate(rate);
1678 }
1679 
getStreamDuration() const1680 int BambooTracker::getStreamDuration() const
1681 {
1682 	return opnaCtrl_->getDuration();
1683 }
1684 
setStreamDuration(int duration)1685 void BambooTracker::setStreamDuration(int duration)
1686 {
1687 	opnaCtrl_->setDuration(duration);
1688 }
1689 
getStreamTempo() const1690 int BambooTracker::getStreamTempo() const
1691 {
1692 	return tickCounter_->getTempo();
1693 }
1694 
getStreamSpeed() const1695 int BambooTracker::getStreamSpeed() const
1696 {
1697 	return tickCounter_->getSpeed();
1698 }
1699 
getStreamGrooveEnabled() const1700 bool BambooTracker::getStreamGrooveEnabled() const
1701 {
1702 	return tickCounter_->getGrooveEnabled();
1703 }
1704 
setMasterVolume(int percentage)1705 void BambooTracker::setMasterVolume(int percentage)
1706 {
1707 	opnaCtrl_->setMasterVolume(percentage);
1708 }
1709 
setMasterVolumeFM(double dB)1710 void BambooTracker::setMasterVolumeFM(double dB)
1711 {
1712 	opnaCtrl_->setMasterVolumeFM(dB);
1713 }
1714 
setMasterVolumeSSG(double dB)1715 void BambooTracker::setMasterVolumeSSG(double dB)
1716 {
1717 	opnaCtrl_->setMasterVolumeSSG(dB);
1718 }
1719 
1720 /********** Module details **********/
1721 /*----- Module -----*/
makeNewModule()1722 void BambooTracker::makeNewModule()
1723 {
1724 	stopPlaySong();
1725 
1726 	clearAllInstrument();
1727 
1728 	opnaCtrl_->reset();
1729 
1730 	mod_ = std::make_shared<Module>();
1731 
1732 	tickCounter_->setInterruptRate(mod_->getTickFrequency());
1733 
1734 	setCurrentSongNumber(0);
1735 	curInstNum_ = -1;
1736 
1737 	clearCommandHistory();
1738 }
1739 
loadModule(BinaryContainer & container)1740 void BambooTracker::loadModule(BinaryContainer& container)
1741 {
1742 	makeNewModule();
1743 
1744 	std::exception_ptr ep;
1745 	try {
1746 		ModuleIO::loadModule(container, mod_, instMan_);
1747 	}
1748 	catch (...) {
1749 		ep = std::current_exception();
1750 	}
1751 
1752 	tickCounter_->setInterruptRate(mod_->getTickFrequency());
1753 	setCurrentSongNumber(0);
1754 	clearCommandHistory();
1755 
1756 	if (ep) std::rethrow_exception(ep);
1757 }
1758 
saveModule(BinaryContainer & container)1759 void BambooTracker::saveModule(BinaryContainer& container)
1760 {
1761 	ModuleIO::saveModule(container, mod_, instMan_);
1762 }
1763 
setModulePath(std::string path)1764 void BambooTracker::setModulePath(std::string path)
1765 {
1766 	mod_->setFilePath(path);
1767 }
1768 
getModulePath() const1769 std::string BambooTracker::getModulePath() const
1770 {
1771 	return mod_->getFilePath();
1772 }
1773 
setModuleTitle(std::string title)1774 void BambooTracker::setModuleTitle(std::string title)
1775 {
1776 	mod_->setTitle(title);
1777 }
1778 
getModuleTitle() const1779 std::string BambooTracker::getModuleTitle() const
1780 {
1781 	return mod_->getTitle();
1782 }
1783 
setModuleAuthor(std::string author)1784 void BambooTracker::setModuleAuthor(std::string author)
1785 {
1786 	mod_->setAuthor(author);
1787 }
1788 
getModuleAuthor() const1789 std::string BambooTracker::getModuleAuthor() const
1790 {
1791 	return mod_->getAuthor();
1792 }
1793 
setModuleCopyright(std::string copyright)1794 void BambooTracker::setModuleCopyright(std::string copyright)
1795 {
1796 	mod_->setCopyright(copyright);
1797 }
1798 
getModuleCopyright() const1799 std::string BambooTracker::getModuleCopyright() const
1800 {
1801 	return mod_->getCopyright();
1802 }
1803 
setModuleComment(std::string comment)1804 void BambooTracker::setModuleComment(std::string comment)
1805 {
1806 	mod_->setComment(comment);
1807 }
1808 
getModuleComment() const1809 std::string BambooTracker::getModuleComment() const
1810 {
1811 	return mod_->getComment();
1812 }
1813 
setModuleTickFrequency(unsigned int freq)1814 void BambooTracker::setModuleTickFrequency(unsigned int freq)
1815 {
1816 	mod_->setTickFrequency(freq);
1817 	tickCounter_->setInterruptRate(freq);
1818 }
1819 
getModuleTickFrequency() const1820 unsigned int BambooTracker::getModuleTickFrequency() const
1821 {
1822 	return mod_->getTickFrequency();
1823 }
1824 
setModuleStepHighlight1Distance(size_t dist)1825 void BambooTracker::setModuleStepHighlight1Distance(size_t dist)
1826 {
1827 	mod_->setStepHighlight1Distance(dist);
1828 }
1829 
getModuleStepHighlight1Distance() const1830 size_t BambooTracker::getModuleStepHighlight1Distance() const
1831 {
1832 	return mod_->getStepHighlight1Distance();
1833 }
1834 
setModuleStepHighlight2Distance(size_t dist)1835 void BambooTracker::setModuleStepHighlight2Distance(size_t dist)
1836 {
1837 	mod_->setStepHighlight2Distance(dist);
1838 }
1839 
getModuleStepHighlight2Distance() const1840 size_t BambooTracker::getModuleStepHighlight2Distance() const
1841 {
1842 	return mod_->getStepHighlight2Distance();
1843 }
1844 
setModuleMixerType(MixerType type)1845 void BambooTracker::setModuleMixerType(MixerType type)
1846 {
1847 	mod_->setMixerType(type);
1848 }
1849 
getModuleMixerType() const1850 MixerType BambooTracker::getModuleMixerType() const
1851 {
1852 	return mod_->getMixerType();
1853 }
1854 
setModuleCustomMixerFMLevel(double level)1855 void BambooTracker::setModuleCustomMixerFMLevel(double level)
1856 {
1857 	mod_->setCustomMixerFMLevel(level);
1858 }
1859 
getModuleCustomMixerFMLevel() const1860 double BambooTracker::getModuleCustomMixerFMLevel() const
1861 {
1862 	return mod_->getCustomMixerFMLevel();
1863 }
1864 
setModuleCustomMixerSSGLevel(double level)1865 void BambooTracker::setModuleCustomMixerSSGLevel(double level)
1866 {
1867 	mod_->setCustomMixerSSGLevel(level);
1868 }
1869 
getModuleCustomMixerSSGLevel() const1870 double BambooTracker::getModuleCustomMixerSSGLevel() const
1871 {
1872 	return mod_->getCustomMixerSSGLevel();
1873 }
1874 
getGrooveCount() const1875 size_t BambooTracker::getGrooveCount() const
1876 {
1877 	return mod_->getGrooveCount();
1878 }
1879 
setGroove(int num,std::vector<int> seq)1880 void BambooTracker::setGroove(int num, std::vector<int> seq)
1881 {
1882 	mod_->setGroove(num, std::move(seq));
1883 }
1884 
setGrooves(std::vector<std::vector<int>> seqs)1885 void BambooTracker::setGrooves(std::vector<std::vector<int>> seqs)
1886 {
1887 	mod_->setGrooves(std::move(seqs));
1888 }
1889 
getGroove(int num) const1890 std::vector<int> BambooTracker::getGroove(int num) const
1891 {
1892 	return mod_->getGroove(num).getSequence();
1893 }
1894 
clearUnusedPatterns()1895 void BambooTracker::clearUnusedPatterns()
1896 {
1897 	mod_->clearUnusedPatterns();
1898 }
1899 
replaceDuplicateInstrumentsInPatterns(std::vector<std::vector<int>> list)1900 void BambooTracker::replaceDuplicateInstrumentsInPatterns(std::vector<std::vector<int>> list)
1901 {
1902 	std::unordered_map<int, int> map;
1903 	for (auto& group : list) {
1904 		for (size_t i = 1; i < group.size(); ++i) {
1905 			map.emplace(group[i], group.front());
1906 		}
1907 	}
1908 
1909 	mod_->replaceDuplicateInstrumentsInPatterns(map);
1910 }
1911 
clearUnusedADPCMSamples()1912 void BambooTracker::clearUnusedADPCMSamples()
1913 {
1914 	instMan_->clearUnusedSamplesADPCM();
1915 }
1916 
1917 /*----- Song -----*/
setSongTitle(int songNum,std::string title)1918 void BambooTracker::setSongTitle(int songNum, std::string title)
1919 {
1920 	mod_->getSong(songNum).setTitle(title);
1921 }
1922 
getSongTitle(int songNum) const1923 std::string BambooTracker::getSongTitle(int songNum) const
1924 {
1925 	return mod_->getSong(songNum).getTitle();
1926 }
1927 
setSongTempo(int songNum,int tempo)1928 void BambooTracker::setSongTempo(int songNum, int tempo)
1929 {
1930 	mod_->getSong(songNum).setTempo(tempo);
1931 	if (curSongNum_ == songNum) tickCounter_->setTempo(tempo);
1932 }
1933 
getSongTempo(int songNum) const1934 int BambooTracker::getSongTempo(int songNum) const
1935 {
1936 	return mod_->getSong(songNum).getTempo();
1937 }
1938 
setSongGroove(int songNum,int groove)1939 void BambooTracker::setSongGroove(int songNum, int groove)
1940 {
1941 	mod_->getSong(songNum).setGroove(groove);
1942 	tickCounter_->setGroove(mod_->getGroove(groove).getSequence());
1943 }
1944 
getSongGroove(int songNum) const1945 int BambooTracker::getSongGroove(int songNum) const
1946 {
1947 	return mod_->getSong(songNum).getGroove();
1948 }
1949 
toggleTempoOrGrooveInSong(int songNum,bool isTempo)1950 void BambooTracker::toggleTempoOrGrooveInSong(int songNum, bool isTempo)
1951 {
1952 	mod_->getSong(songNum).toggleTempoOrGroove(isTempo);
1953 	tickCounter_->setGrooveTrigger(isTempo ? GrooveTrigger::Invalid
1954 										   : GrooveTrigger::ValidByGlobal);
1955 }
1956 
isUsedTempoInSong(int songNum) const1957 bool BambooTracker::isUsedTempoInSong(int songNum) const
1958 {
1959 	return mod_->getSong(songNum).isUsedTempo();
1960 }
1961 
getSongStyle(int songNum) const1962 SongStyle BambooTracker::getSongStyle(int songNum) const
1963 {
1964 	return mod_->getSong(songNum).getStyle();
1965 }
1966 
changeSongType(int songNum,SongType type)1967 void BambooTracker::changeSongType(int songNum, SongType type)
1968 {
1969 	mod_->getSong(songNum).changeType(type);
1970 }
1971 
setSongSpeed(int songNum,int speed)1972 void BambooTracker::setSongSpeed(int songNum, int speed)
1973 {
1974 	mod_->getSong(songNum).setSpeed(speed);
1975 	if (curSongNum_ == songNum) tickCounter_->setSpeed(speed);
1976 }
1977 
getSongSpeed(int songNum) const1978 int BambooTracker::getSongSpeed(int songNum) const
1979 {
1980 	return mod_->getSong(songNum).getSpeed();
1981 }
1982 
getSongCount() const1983 size_t BambooTracker::getSongCount() const
1984 {
1985 	return mod_->getSongCount();
1986 }
1987 
addSong(SongType songType,std::string title)1988 void BambooTracker::addSong(SongType songType, std::string title)
1989 {
1990 	mod_->addSong(songType, title);
1991 }
1992 
sortSongs(std::vector<int> numbers)1993 void BambooTracker::sortSongs(std::vector<int> numbers)
1994 {
1995 	mod_->sortSongs(std::move(numbers));
1996 }
1997 
getAllStepCount(int songNum,size_t loopCnt) const1998 size_t BambooTracker::getAllStepCount(int songNum, size_t loopCnt) const
1999 {
2000 	size_t introSize = 0;
2001 	size_t loopSize = 0;
2002 	int dummy1 = 0;
2003 	int dummy2 = 0;
2004 	checkNextPositionOfLastStepAndStepSize(songNum, dummy1, dummy2, introSize, loopSize);
2005 	return introSize + loopSize * loopCnt;
2006 }
2007 
transposeSong(int songNum,int seminotes,std::vector<int> excludeInsts)2008 void BambooTracker::transposeSong(int songNum, int seminotes, std::vector<int> excludeInsts)
2009 {
2010 	mod_->getSong(songNum).transpose(seminotes, excludeInsts);
2011 }
2012 
swapTracks(int songNum,int track1,int track2)2013 void BambooTracker::swapTracks(int songNum, int track1, int track2)
2014 {
2015 	mod_->getSong(songNum).swapTracks(track1, track2);
2016 }
2017 
calculateSongLength(int songNum) const2018 double BambooTracker::calculateSongLength(int songNum) const
2019 {
2020 	SongLengthCalculator calculator(*mod_.get(), songNum);
2021 	return calculator.calculateBySecond();
2022 }
2023 
2024 /*----- Bookmark -----*/
addBookmark(int songNum,std::string name,int order,int step)2025 void BambooTracker::addBookmark(int songNum, std::string name, int order, int step)
2026 {
2027 	mod_->getSong(songNum).addBookmark(name, order, step);
2028 }
2029 
changeBookmark(int songNum,int i,std::string name,int order,int step)2030 void BambooTracker::changeBookmark(int songNum, int i, std::string name, int order, int step)
2031 {
2032 	mod_->getSong(songNum).changeBookmark(i, name, order, step);
2033 }
2034 
removeBookmark(int songNum,int i)2035 void BambooTracker::removeBookmark(int songNum, int i)
2036 {
2037 	mod_->getSong(songNum).removeBookmark(i);
2038 }
2039 
clearBookmark(int songNum)2040 void BambooTracker::clearBookmark(int songNum)
2041 {
2042 	mod_->getSong(songNum).clearBookmark();
2043 }
2044 
swapBookmarks(int songNum,int a,int b)2045 void BambooTracker::swapBookmarks(int songNum, int a, int b)
2046 {
2047 	mod_->getSong(songNum).swapBookmarks(a, b);
2048 }
2049 
sortBookmarkByPosition(int songNum)2050 void BambooTracker::sortBookmarkByPosition(int songNum)
2051 {
2052 	mod_->getSong(songNum).sortBookmarkByPosition();
2053 }
sortBookmarkByName(int songNum)2054 void BambooTracker::sortBookmarkByName(int songNum)
2055 {
2056 	mod_->getSong(songNum).sortBookmarkByName();
2057 }
2058 
getBookmark(int songNum,int i) const2059 Bookmark BambooTracker::getBookmark(int songNum, int i) const
2060 {
2061 	return mod_->getSong(songNum).getBookmark(i);
2062 }
2063 
findBookmarks(int songNum,int order,int step)2064 std::vector<int> BambooTracker::findBookmarks(int songNum, int order, int step)
2065 {
2066 	return mod_->getSong(songNum).findBookmarks(order, step);
2067 }
2068 
getPreviousBookmark(int songNum,int order,int step)2069 Bookmark BambooTracker::getPreviousBookmark(int songNum, int order, int step)
2070 {
2071 	return mod_->getSong(songNum).getPreviousBookmark(order, step);
2072 }
2073 
getNextBookmark(int songNum,int order,int step)2074 Bookmark BambooTracker::getNextBookmark(int songNum, int order, int step)
2075 {
2076 	return mod_->getSong(songNum).getNextBookmark(order, step);
2077 }
2078 
getBookmarkSize(int songNum) const2079 size_t BambooTracker::getBookmarkSize(int songNum) const
2080 {
2081 	return mod_->getSong(songNum).getBookmarkSize();
2082 }
2083 
2084 /*----- Track -----*/
setEffectDisplayWidth(int songNum,int trackNum,size_t w)2085 void BambooTracker::setEffectDisplayWidth(int songNum, int trackNum, size_t w)
2086 {
2087 	mod_->getSong(songNum).getTrack(trackNum).setEffectDisplayWidth(w);
2088 }
2089 
getEffectDisplayWidth(int songNum,int trackNum) const2090 size_t BambooTracker::getEffectDisplayWidth(int songNum, int trackNum) const
2091 {
2092 	return mod_->getSong(songNum).getTrack(trackNum).getEffectDisplayWidth();
2093 }
2094 
2095 /*----- Order -----*/
getOrderData(int songNum,int orderNum) const2096 std::vector<OrderData> BambooTracker::getOrderData(int songNum, int orderNum) const
2097 {
2098 	return mod_->getSong(songNum).getOrderData(orderNum);
2099 }
2100 
setOrderPatternDigit(int songNum,int trackNum,int orderNum,int patternNum,bool secondEntry)2101 void BambooTracker::setOrderPatternDigit(int songNum, int trackNum, int orderNum, int patternNum, bool secondEntry)
2102 {
2103 	comMan_.invoke(std::make_unique<SetPatternToOrderCommand>(mod_, songNum, trackNum, orderNum, patternNum, secondEntry));
2104 }
2105 
insertOrderBelow(int songNum,int orderNum)2106 void BambooTracker::insertOrderBelow(int songNum, int orderNum)
2107 {
2108 	comMan_.invoke(std::make_unique<InsertOrderBelowCommand>(mod_, songNum, orderNum));
2109 }
2110 
deleteOrder(int songNum,int orderNum)2111 void BambooTracker::deleteOrder(int songNum, int orderNum)
2112 {
2113 	comMan_.invoke(std::make_unique<DeleteOrderCommand>(mod_, songNum, orderNum));
2114 }
2115 
pasteOrderCells(int songNum,int beginTrack,int beginOrder,std::vector<std::vector<std::string>> cells)2116 void BambooTracker::pasteOrderCells(int songNum, int beginTrack, int beginOrder,
2117 									std::vector<std::vector<std::string>> cells)
2118 {
2119 	// Arrange data
2120 	std::vector<std::vector<std::string>> d;
2121 	size_t w = songStyle_.trackAttribs.size() - static_cast<size_t>(beginTrack);
2122 	size_t h = getOrderSize(songNum) - static_cast<size_t>(beginOrder);
2123 
2124 	size_t width = std::min(cells.at(0).size(), w);
2125 	size_t height = std::min(cells.size(), h);
2126 
2127 	for (size_t i = 0; i < height; ++i) {
2128 		d.emplace_back();
2129 		for (size_t j = 0; j < width; ++j) {
2130 			d.at(i).push_back(cells.at(i).at(j));
2131 		}
2132 	}
2133 
2134 	comMan_.invoke(std::make_unique<PasteCopiedDataToOrderCommand>(mod_, songNum, beginTrack, beginOrder, std::move(d)));
2135 }
2136 
duplicateOrder(int songNum,int orderNum)2137 void BambooTracker::duplicateOrder(int songNum, int orderNum)
2138 {
2139 	comMan_.invoke(std::make_unique<DuplicateOrderCommand>(mod_, songNum, orderNum));
2140 }
2141 
MoveOrder(int songNum,int orderNum,bool isUp)2142 void BambooTracker::MoveOrder(int songNum, int orderNum, bool isUp)
2143 {
2144 	comMan_.invoke(std::make_unique<MoveOrderCommand>(mod_, songNum, orderNum, isUp));
2145 }
2146 
clonePatterns(int songNum,int beginOrder,int beginTrack,int endOrder,int endTrack)2147 void BambooTracker::clonePatterns(int songNum, int beginOrder, int beginTrack, int endOrder, int endTrack)
2148 {
2149 	comMan_.invoke(std::make_unique<ClonePatternsCommand>(mod_, songNum, beginOrder, beginTrack, endOrder, endTrack));
2150 }
2151 
cloneOrder(int songNum,int orderNum)2152 void BambooTracker::cloneOrder(int songNum, int orderNum)
2153 {
2154 	comMan_.invoke(std::make_unique<CloneOrderCommand>(mod_, songNum, orderNum));
2155 }
2156 
getOrderSize(int songNum) const2157 size_t BambooTracker::getOrderSize(int songNum) const
2158 {
2159 	return mod_->getSong(songNum).getOrderSize();
2160 }
2161 
canAddNewOrder(int songNum) const2162 bool BambooTracker::canAddNewOrder(int songNum) const
2163 {
2164 	return mod_->getSong(songNum).canAddNewOrder();
2165 }
2166 
2167 /*----- Pattern -----*/
getStepNoteNumber(int songNum,int trackNum,int orderNum,int stepNum) const2168 int BambooTracker::getStepNoteNumber(int songNum, int trackNum, int orderNum, int stepNum) const
2169 {
2170 	return mod_->getSong(songNum).getTrack(trackNum).getPatternFromOrderNumber(orderNum)
2171 			.getStep(stepNum).getNoteNumber();
2172 }
2173 
setStepNote(int songNum,int trackNum,int orderNum,int stepNum,int octave,Note note,bool instMask,bool volMask)2174 void BambooTracker::setStepNote(int songNum, int trackNum, int orderNum, int stepNum, int octave, Note note, bool instMask, bool volMask)
2175 {
2176 	int nn = octaveAndNoteToNoteNumber(octave, note);
2177 	SoundSource src = songStyle_.trackAttribs.at(static_cast<size_t>(trackNum)).source;
2178 
2179 	int in = -1;
2180 	if (!instMask && curInstNum_ != -1
2181 			&& (src == instMan_->getInstrumentSharedPtr(curInstNum_)->getSoundSource())) {
2182 		in = curInstNum_;
2183 	}
2184 	bool fmReversed = (volFMReversed_ && src == SoundSource::FM);
2185 
2186 	comMan_.invoke(std::make_unique<SetKeyOnToStepCommand>(mod_, songNum, trackNum, orderNum, stepNum, nn, instMask, in, volMask, curVolume_, fmReversed));
2187 }
2188 
setStepKeyOff(int songNum,int trackNum,int orderNum,int stepNum)2189 void BambooTracker::setStepKeyOff(int songNum, int trackNum, int orderNum, int stepNum)
2190 {
2191 	comMan_.invoke(std::make_unique<SetKeyOffToStepCommand>(mod_, songNum, trackNum, orderNum, stepNum));
2192 }
2193 
setEchoBufferAccess(int songNum,int trackNum,int orderNum,int stepNum,int bufNum)2194 void BambooTracker::setEchoBufferAccess(int songNum, int trackNum, int orderNum, int stepNum, int bufNum)
2195 {
2196 	comMan_.invoke(std::make_unique<SetEchoBufferAccessCommand>(mod_, songNum, trackNum, orderNum, stepNum, bufNum));
2197 }
2198 
eraseStepNote(int songNum,int trackNum,int orderNum,int stepNum)2199 void BambooTracker::eraseStepNote(int songNum, int trackNum, int orderNum, int stepNum)
2200 {
2201 	comMan_.invoke(std::make_unique<EraseStepCommand>(mod_, songNum, trackNum, orderNum, stepNum));
2202 }
2203 
getStepInstrument(int songNum,int trackNum,int orderNum,int stepNum) const2204 int BambooTracker::getStepInstrument(int songNum, int trackNum, int orderNum, int stepNum) const
2205 {
2206 	return mod_->getSong(songNum).getTrack(trackNum).getPatternFromOrderNumber(orderNum)
2207 			.getStep(stepNum).getInstrumentNumber();
2208 }
2209 
setStepInstrumentDigit(int songNum,int trackNum,int orderNum,int stepNum,int instNum,bool secondEntry)2210 void BambooTracker::setStepInstrumentDigit(int songNum, int trackNum, int orderNum, int stepNum, int instNum, bool secondEntry)
2211 {
2212 	comMan_.invoke(std::make_unique<SetInstrumentToStepCommand>(mod_, songNum, trackNum, orderNum, stepNum, instNum, secondEntry));
2213 }
2214 
eraseStepInstrument(int songNum,int trackNum,int orderNum,int stepNum)2215 void BambooTracker::eraseStepInstrument(int songNum, int trackNum, int orderNum, int stepNum)
2216 {
2217 	comMan_.invoke(std::make_unique<EraseInstrumentInStepCommand>(mod_, songNum, trackNum, orderNum, stepNum));
2218 }
2219 
getStepVolume(int songNum,int trackNum,int orderNum,int stepNum) const2220 int BambooTracker::getStepVolume(int songNum, int trackNum, int orderNum, int stepNum) const
2221 {
2222 	return mod_->getSong(songNum).getTrack(trackNum).getPatternFromOrderNumber(orderNum)
2223 			.getStep(stepNum).getVolume();
2224 }
2225 
setStepVolumeDigit(int songNum,int trackNum,int orderNum,int stepNum,int volume,bool secondEntry)2226 int BambooTracker::setStepVolumeDigit(int songNum, int trackNum, int orderNum, int stepNum, int volume, bool secondEntry)
2227 {
2228 	bool fmReversed = (volFMReversed_
2229 					   && songStyle_.trackAttribs.at(static_cast<size_t>(trackNum)).source == SoundSource::FM);
2230 	comMan_.invoke(std::make_unique<SetVolumeToStepCommand>(mod_, songNum, trackNum, orderNum, stepNum, volume, fmReversed, secondEntry));
2231 	curVolume_ = mod_->getSong(songNum).getTrack(trackNum).getPatternFromOrderNumber(orderNum).getStep(stepNum).getVolume();
2232 	if (fmReversed && curVolume_ < 0x80) curVolume_ = 0x7f - curVolume_;
2233 	return curVolume_;
2234 }
2235 
eraseStepVolume(int songNum,int trackNum,int orderNum,int stepNum)2236 void BambooTracker::eraseStepVolume(int songNum, int trackNum, int orderNum, int stepNum)
2237 {
2238 	comMan_.invoke(std::make_unique<EraseVolumeInStepCommand>(mod_, songNum, trackNum, orderNum, stepNum));
2239 }
2240 
getStepEffectID(int songNum,int trackNum,int orderNum,int stepNum,int n) const2241 std::string BambooTracker::getStepEffectID(int songNum, int trackNum, int orderNum, int stepNum, int n) const
2242 {
2243 	return mod_->getSong(songNum).getTrack(trackNum).getPatternFromOrderNumber(orderNum)
2244 			.getStep(stepNum).getEffectID(n);
2245 }
2246 
setStepEffectIDCharacter(int songNum,int trackNum,int orderNum,int stepNum,int n,std::string id,bool fillValue00,bool secondEntry)2247 void BambooTracker::setStepEffectIDCharacter(int songNum, int trackNum, int orderNum, int stepNum, int n, std::string id, bool fillValue00, bool secondEntry)
2248 {
2249 	comMan_.invoke(std::make_unique<SetEffectIDToStepCommand>(mod_, songNum, trackNum, orderNum, stepNum, n, id, fillValue00, secondEntry));
2250 }
2251 
getStepEffectValue(int songNum,int trackNum,int orderNum,int stepNum,int n) const2252 int BambooTracker::getStepEffectValue(int songNum, int trackNum, int orderNum, int stepNum, int n) const
2253 {
2254 	return mod_->getSong(songNum).getTrack(trackNum).getPatternFromOrderNumber(orderNum)
2255 			.getStep(stepNum).getEffectValue(n);
2256 }
2257 
setStepEffectValueDigit(int songNum,int trackNum,int orderNum,int stepNum,int n,int value,EffectDisplayControl ctrl,bool secondEntry)2258 void BambooTracker::setStepEffectValueDigit(int songNum, int trackNum, int orderNum, int stepNum, int n, int value, EffectDisplayControl ctrl, bool secondEntry)
2259 {
2260 	comMan_.invoke(std::make_unique<SetEffectValueToStepCommand>(mod_, songNum, trackNum, orderNum, stepNum, n, value, ctrl, secondEntry));
2261 }
2262 
eraseStepEffect(int songNum,int trackNum,int orderNum,int stepNum,int n)2263 void BambooTracker::eraseStepEffect(int songNum, int trackNum, int orderNum, int stepNum, int n)
2264 {
2265 	comMan_.invoke(std::make_unique<EraseEffectInStepCommand>(mod_, songNum, trackNum, orderNum, stepNum, n));
2266 }
2267 
eraseStepEffectValue(int songNum,int trackNum,int orderNum,int stepNum,int n)2268 void BambooTracker::eraseStepEffectValue(int songNum, int trackNum, int orderNum, int stepNum, int n)
2269 {
2270 	comMan_.invoke(std::make_unique<EraseEffectValueInStepCommand>(mod_, songNum, trackNum, orderNum, stepNum, n));
2271 }
2272 
insertStep(int songNum,int trackNum,int orderNum,int stepNum)2273 void BambooTracker::insertStep(int songNum, int trackNum, int orderNum, int stepNum)
2274 {
2275 	comMan_.invoke(std::make_unique<InsertStepCommand>(mod_, songNum, trackNum, orderNum, stepNum));
2276 }
2277 
deletePreviousStep(int songNum,int trackNum,int orderNum,int stepNum)2278 void BambooTracker::deletePreviousStep(int songNum, int trackNum, int orderNum, int stepNum)
2279 {
2280 	comMan_.invoke(std::make_unique<DeletePreviousStepCommand>(mod_, songNum, trackNum, orderNum, stepNum));
2281 }
2282 
pastePatternCells(int songNum,int beginTrack,int beginColmn,int beginOrder,int beginStep,std::vector<std::vector<std::string>> cells)2283 void BambooTracker::pastePatternCells(int songNum, int beginTrack, int beginColmn, int beginOrder, int beginStep,
2284 									  std::vector<std::vector<std::string>> cells)
2285 {
2286 	std::vector<std::vector<std::string>> d
2287 			= arrangePatternDataCells(songNum, beginTrack, beginColmn, beginOrder, beginStep, std::move(cells));
2288 
2289 	comMan_.invoke(std::make_unique<PasteCopiedDataToPatternCommand>(
2290 					   mod_, songNum, beginTrack, beginColmn, beginOrder, beginStep, std::move(d)));
2291 }
2292 
pasteMixPatternCells(int songNum,int beginTrack,int beginColmn,int beginOrder,int beginStep,std::vector<std::vector<std::string>> cells)2293 void BambooTracker::pasteMixPatternCells(int songNum, int beginTrack, int beginColmn, int beginOrder, int beginStep,
2294 										 std::vector<std::vector<std::string>> cells)
2295 {
2296 	std::vector<std::vector<std::string>> d
2297 			= arrangePatternDataCells(songNum, beginTrack, beginColmn, beginOrder, beginStep, std::move(cells));
2298 
2299 	comMan_.invoke(std::make_unique<PasteMixCopiedDataToPatternCommand>(
2300 					   mod_, songNum, beginTrack, beginColmn, beginOrder, beginStep, std::move(d)));
2301 }
2302 
pasteOverwritePatternCells(int songNum,int beginTrack,int beginColmn,int beginOrder,int beginStep,std::vector<std::vector<std::string>> cells)2303 void BambooTracker::pasteOverwritePatternCells(int songNum, int beginTrack, int beginColmn, int beginOrder,
2304 											   int beginStep, std::vector<std::vector<std::string>> cells)
2305 {
2306 	std::vector<std::vector<std::string>> d
2307 			= arrangePatternDataCells(songNum, beginTrack, beginColmn, beginOrder, beginStep, std::move(cells));
2308 
2309 	comMan_.invoke(std::make_unique<PasteOverwriteCopiedDataToPatternCommand>(
2310 					   mod_, songNum, beginTrack, beginColmn, beginOrder, beginStep, std::move(d)));
2311 }
2312 
pasteInsertPatternCells(int songNum,int beginTrack,int beginColmn,int beginOrder,int beginStep,std::vector<std::vector<std::string>> cells)2313 void BambooTracker::pasteInsertPatternCells(int songNum, int beginTrack, int beginColmn, int beginOrder,
2314 											int beginStep, std::vector<std::vector<std::string>> cells)
2315 {
2316 	std::vector<std::vector<std::string>> d
2317 			= arrangePatternDataCells(songNum, beginTrack, beginColmn, beginOrder, beginStep, std::move(cells));
2318 
2319 	comMan_.invoke(std::make_unique<PasteInsertCopiedDataToPatternCommand>(
2320 					   mod_, songNum, beginTrack, beginColmn, beginOrder, beginStep, std::move(d)));
2321 }
2322 
arrangePatternDataCells(int songNum,int beginTrack,int beginColmn,int beginOrder,int beginStep,std::vector<std::vector<std::string>> cells)2323 std::vector<std::vector<std::string>> BambooTracker::arrangePatternDataCells(int songNum, int beginTrack, int beginColmn, int beginOrder, int beginStep,
2324 																			 std::vector<std::vector<std::string>> cells)
2325 {
2326 	std::vector<std::vector<std::string>> d;
2327 	size_t w = (songStyle_.trackAttribs.size() - static_cast<size_t>(beginTrack) - 1) * 11
2328 			   + (11 - static_cast<size_t>(beginColmn));
2329 	size_t h = getPatternSizeFromOrderNumber(songNum, beginOrder) - static_cast<size_t>(beginStep);
2330 
2331 	size_t width = std::min(cells.at(0).size(), w);
2332 	size_t height = std::min(cells.size(), h);
2333 
2334 	for (size_t i = 0; i < height; ++i) {
2335 		d.emplace_back();
2336 		for (size_t j = 0; j < width; ++j) {
2337 			d.at(i).push_back(cells.at(i).at(j));
2338 		}
2339 	}
2340 
2341 	return d;
2342 }
2343 
erasePatternCells(int songNum,int beginTrack,int beginColmn,int beginOrder,int beginStep,int endTrack,int endColmn,int endStep)2344 void BambooTracker::erasePatternCells(int songNum, int beginTrack, int beginColmn, int beginOrder, int beginStep,
2345 									  int endTrack, int endColmn, int endStep)
2346 {
2347 	comMan_.invoke(std::make_unique<EraseCellsInPatternCommand>(
2348 					   mod_, songNum, beginTrack, beginColmn, beginOrder, beginStep, endTrack, endColmn, endStep));
2349 }
2350 
transposeNoteInPattern(int songNum,int beginTrack,int beginOrder,int beginStep,int endTrack,int endStep,int seminote)2351 void BambooTracker::transposeNoteInPattern(int songNum, int beginTrack, int beginOrder, int beginStep,
2352 										   int endTrack, int endStep, int seminote)
2353 {
2354 	comMan_.invoke(std::make_unique<TransposeNoteInPatternCommand>(
2355 					   mod_, songNum, beginTrack, beginOrder, beginStep, endTrack, endStep, seminote));
2356 }
2357 
changeValuesInPattern(int songNum,int beginTrack,int beginColumn,int beginOrder,int beginStep,int endTrack,int endColumn,int endStep,int value)2358 void BambooTracker::changeValuesInPattern(int songNum, int beginTrack, int beginColumn, int beginOrder,
2359 										  int beginStep, int endTrack, int endColumn, int endStep, int value)
2360 {
2361 	comMan_.invoke(std::make_unique<ChangeValuesInPatternCommand>(
2362 					   mod_, songNum, beginTrack, beginColumn, beginOrder, beginStep,
2363 					   endTrack, endColumn, endStep, value, volFMReversed_));
2364 }
2365 
expandPattern(int songNum,int beginTrack,int beginColmn,int beginOrder,int beginStep,int endTrack,int endColmn,int endStep)2366 void BambooTracker::expandPattern(int songNum, int beginTrack, int beginColmn, int beginOrder, int beginStep,
2367 								  int endTrack, int endColmn, int endStep)
2368 {
2369 	comMan_.invoke(std::make_unique<ExpandPatternCommand>(
2370 					   mod_, songNum, beginTrack, beginColmn, beginOrder, beginStep, endTrack, endColmn, endStep));
2371 }
2372 
shrinkPattern(int songNum,int beginTrack,int beginColmn,int beginOrder,int beginStep,int endTrack,int endColmn,int endStep)2373 void BambooTracker::shrinkPattern(int songNum, int beginTrack, int beginColmn, int beginOrder, int beginStep,
2374 								  int endTrack, int endColmn, int endStep)
2375 {
2376 	comMan_.invoke(std::make_unique<ShrinkPatternCommand>(
2377 					   mod_, songNum, beginTrack, beginColmn, beginOrder, beginStep, endTrack, endColmn, endStep));
2378 }
2379 
interpolatePattern(int songNum,int beginTrack,int beginColmn,int beginOrder,int beginStep,int endTrack,int endColmn,int endStep)2380 void BambooTracker::interpolatePattern(int songNum, int beginTrack, int beginColmn, int beginOrder, int beginStep,
2381 									   int endTrack, int endColmn, int endStep)
2382 {
2383 	comMan_.invoke(std::make_unique<InterpolatePatternCommand>(
2384 					   mod_, songNum, beginTrack, beginColmn, beginOrder, beginStep, endTrack, endColmn, endStep));
2385 }
2386 
reversePattern(int songNum,int beginTrack,int beginColmn,int beginOrder,int beginStep,int endTrack,int endColmn,int endStep)2387 void BambooTracker::reversePattern(int songNum, int beginTrack, int beginColmn, int beginOrder, int beginStep,
2388 								   int endTrack, int endColmn, int endStep)
2389 {
2390 	comMan_.invoke(std::make_unique<ReversePatternCommand>(
2391 					   mod_, songNum, beginTrack, beginColmn, beginOrder, beginStep, endTrack, endColmn, endStep));
2392 }
2393 
replaceInstrumentInPattern(int songNum,int beginTrack,int beginOrder,int beginStep,int endTrack,int endStep,int newInstNum)2394 void BambooTracker::replaceInstrumentInPattern(int songNum, int beginTrack, int beginOrder, int beginStep,
2395 											   int endTrack, int endStep, int newInstNum)
2396 {
2397 	comMan_.invoke(std::make_unique<ReplaceInstrumentInPatternCommand>(
2398 					   mod_, songNum, beginTrack, beginOrder, beginStep, endTrack, endStep, newInstNum));
2399 }
2400 
getPatternSizeFromOrderNumber(int songNum,int orderNum) const2401 size_t BambooTracker::getPatternSizeFromOrderNumber(int songNum, int orderNum) const
2402 {
2403 	return mod_->getSong(songNum).getPatternSizeFromOrderNumber(orderNum);
2404 }
2405 
setDefaultPatternSize(int songNum,size_t size)2406 void BambooTracker::setDefaultPatternSize(int songNum, size_t size)
2407 {
2408 	mod_->getSong(songNum).setDefaultPatternSize(size);
2409 	playback_->checkPlayPosition(static_cast<int>(size));
2410 }
2411 
getDefaultPatternSize(int songNum) const2412 size_t BambooTracker::getDefaultPatternSize(int songNum) const
2413 {
2414 	return mod_->getSong(songNum).getDefaultPatternSize();
2415 }
2416 
getOutputHistory(int16_t * container)2417 void BambooTracker::getOutputHistory(int16_t* container)
2418 {
2419 	opnaCtrl_->getOutputHistory(container);
2420 }
2421