/[svn]/libgig/trunk/src/SF.cpp
ViewVC logotype

Annotation of /libgig/trunk/src/SF.cpp

Parent Directory Parent Directory | Revision Log Revision Log


Revision 2026 - (hide annotations) (download)
Tue Nov 3 19:08:44 2009 UTC (10 years, 10 months ago) by iliev
File size: 55387 byte(s)
* sf2: better support for preset regions

1 iliev 2016 /***************************************************************************
2     * *
3     * libsf2 - C++ cross-platform SF2 format file access library *
4     * *
5     * Copyright (C) 2009 Grigor Iliev <grigor@grigoriliev.com> *
6     * Copyright (C) 2009 Christian Schoenebeck *
7     * Copyright (C) 2009 Andreas Persson *
8     * *
9     * This library is free software; you can redistribute it and/or modify *
10     * it under the terms of the GNU General Public License as published by *
11     * the Free Software Foundation; either version 2 of the License, or *
12     * (at your option) any later version. *
13     * *
14     * This library is distributed in the hope that it will be useful, *
15     * but WITHOUT ANY WARRANTY; without even the implied warranty of *
16     * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
17     * GNU General Public License for more details. *
18     * *
19     * You should have received a copy of the GNU General Public License *
20     * along with this library; if not, write to the Free Software *
21     * Foundation, Inc., 59 Temple Place, Suite 330, Boston, *
22     * MA 02111-1307 USA *
23     ***************************************************************************/
24    
25     #include <vector>
26    
27     #include "RIFF.h"
28    
29     #include "SF.h"
30    
31     #include "helper.h"
32     #include <math.h>
33    
34     #define _1200TH_ROOT_OF_2 1.000577789506555
35     #define _200TH_ROOT_OF_10 1.011579454259899
36    
37     namespace sf2 {
38     double ToSeconds(int Timecents) {
39 iliev 2026 if (Timecents == NONE) return NONE;
40 iliev 2016 if (Timecents == 0) return 1.0;
41     if (Timecents == -32768) return 0.0;
42     return pow(_1200TH_ROOT_OF_2, Timecents);
43     }
44    
45     double ToPermilles(int Centibels) {
46 iliev 2026 if (Centibels == NONE) return NONE;
47 iliev 2016 if (Centibels == 0) return 1000.0;
48     if (Centibels < 0) return 0.0;
49     return pow(_200TH_ROOT_OF_10, Centibels);
50     }
51    
52 iliev 2026 double ToHz(int cents) {
53     if (cents == NONE) return NONE;
54     if (cents == 0) return 8.176;
55     return pow(_1200TH_ROOT_OF_2, cents) * 8.176;
56     }
57    
58 iliev 2016 RIFF::Chunk* GetMandatoryChunk(RIFF::List* list, uint32_t chunkId) {
59     RIFF::Chunk* ck = list->GetSubChunk(chunkId);
60     if(ck == NULL) throw Exception("Mandatory chunk in RIFF list chunk not found: " + ToString(chunkId));
61     return ck;
62     }
63    
64     void LoadString(RIFF::Chunk* ck, std::string& s, int strLength) {
65     if(ck == NULL) return;
66     char* buf = new char[strLength];
67     int len = 0;
68     for(int i = 0; i < strLength; i++) {
69     buf[i] = ck->ReadInt8();
70     if(buf[i] == 0 && !len) len = i;
71     }
72     if(!len) len = strLength;
73     s.assign(buf, len);
74     delete [] buf;
75     }
76    
77     /**
78     * Throws an error if the chunk is NULL or
79     * the chunk data size is less than size (in bytes).
80     */
81     void VerifySize(RIFF::Chunk* ck, int size) {
82     if (ck == NULL) throw Exception("NULL chunk");
83     if (ck->GetSize() < size) {
84     throw Exception("Invalid chunk size. Chunk ID: " + ToString(ck->GetChunkID()));
85     }
86     }
87    
88     Modulator::Modulator(SFModulator mod) {
89     Type = mod >> 10; // The last 6 bits
90     Polarity = mod & (1 << 9);
91     Direction = mod & (1 << 8);
92     MidiPalete = mod & (1 << 7); // two paletes - general or MIDI
93     Index = mod & 0x7f; /* index field */;
94    
95     }
96    
97     ModulatorItem::ModulatorItem(ModList& mod) :
98     ModSrcOper(Modulator(mod.ModSrcOper)),
99     ModAmtSrcOper(Modulator(mod.ModAmtSrcOper))
100     {
101    
102     }
103    
104     Version::Version(RIFF::Chunk* ck) {
105     if(ck != NULL) VerifySize(ck, 4);
106     Major = ck ? ck->ReadUint16() : 0;
107     Minor = ck ? ck->ReadUint16() : 0;
108     }
109    
110     // *************** Info ***************
111     // *
112    
113     /** @brief Constructor.
114     *
115     * Initializes the info strings with values provided by an INFO list chunk.
116     *
117     * @param list - pointer to a list chunk which contains an INFO list chunk
118     */
119     Info::Info(RIFF::List* list) {
120     if (list) {
121     RIFF::List* lstINFO = list->GetSubList(LIST_TYPE_INFO);
122     if (lstINFO) {
123     pVer = new Version(GetMandatoryChunk(lstINFO, CHUNK_ID_IFIL));
124     LoadString(CHUNK_ID_ISNG, lstINFO, SoundEngine);
125     LoadString(CHUNK_ID_INAM, lstINFO, BankName);
126     LoadString(CHUNK_ID_IROM, lstINFO, RomName);
127     pRomVer = new Version(lstINFO->GetSubChunk(CHUNK_ID_IVER));
128     LoadString(CHUNK_ID_ICRD, lstINFO, CreationDate);
129     LoadString(CHUNK_ID_IENG, lstINFO, Engineers);
130     LoadString(CHUNK_ID_IPRD, lstINFO, Product);
131     LoadString(CHUNK_ID_ICOP, lstINFO, Copyright);
132     LoadString(CHUNK_ID_ICMT, lstINFO, Comments);
133     LoadString(CHUNK_ID_ISFT, lstINFO, Software);
134    
135     }
136     }
137     }
138    
139     Info::~Info() {
140     delete pVer;
141     delete pRomVer;
142     }
143    
144     /** @brief Load given INFO field.
145     *
146     * Load INFO field from INFO chunk with chunk ID \a ChunkID from INFO
147     * list chunk \a lstINFO and save value to \a s.
148     */
149     void Info::LoadString(uint32_t ChunkID, RIFF::List* lstINFO, String& s) {
150     RIFF::Chunk* ck = lstINFO->GetSubChunk(ChunkID);
151     ::LoadString(ck, s); // function from helper.h
152     }
153    
154     Sample::Sample(RIFF::Chunk* ck, RIFF::Chunk* pCkSmpl, RIFF::Chunk* pCkSm24) {
155     this->pCkSmpl = pCkSmpl;
156     this->pCkSm24 = pCkSm24;
157    
158     LoadString(ck, Name, 20);
159     Start = ck->ReadInt32();
160     End = ck->ReadInt32();
161     StartLoop = ck->ReadInt32();
162     EndLoop = ck->ReadInt32();
163     SampleRate = ck->ReadInt32();
164     OriginalPitch = ck->ReadInt8();
165     PitchCorrection = ck->ReadInt8();
166     SampleLink = ck->ReadInt16();
167     SampleType = ck->ReadInt16();
168    
169     if (Start > End || !pCkSmpl || pCkSmpl->GetSize() <= End) {
170     throw Exception("Broken SF2 file (invalid sample info)");
171     }
172    
173     ChannelCount = 1;
174     switch(SampleType) {
175     case 0 : // terminal sample
176     case sf2::Sample::MONO_SAMPLE :
177     case sf2::Sample::ROM_MONO_SAMPLE : break;
178     case sf2::Sample::RIGHT_SAMPLE :
179     case sf2::Sample::LEFT_SAMPLE :
180     case sf2::Sample::ROM_RIGHT_SAMPLE :
181     case sf2::Sample::ROM_LEFT_SAMPLE : ChannelCount = 2; break;
182     case sf2::Sample::LINKED_SAMPLE :
183     case sf2::Sample::ROM_LINKED_SAMPLE : std::cerr << "Linked samples not implemented yet"; break;
184     default: throw Exception("Broken SF2 file (invalid sample type)");
185     }
186    
187     RAMCache.Size = 0;
188     RAMCache.pStart = NULL;
189     RAMCache.NullExtensionSize = 0;
190     }
191    
192     int Sample::GetChannelCount() {
193     return ChannelCount;
194     }
195    
196     long Sample::GetTotalFrameCount() {
197     return (End - Start);
198     }
199    
200     /**
201     * @returns The frame size in bytes
202     */
203     int Sample::GetFrameSize() {
204     return ChannelCount * ((pCkSm24 != NULL) ? 3 : 2);
205     }
206    
207     bool Sample::HasLoops() {
208     return StartLoop != 0 && EndLoop != 0;
209     }
210    
211     /**
212     * Reads \a SampleCount number of sample points from the position stored
213     * in \a pPlaybackState into the buffer pointed by \a pBuffer and moves
214     * the position within the sample respectively, this method honors the
215     * looping informations of the sample (if any). Use this
216     * method if you don't want to load the sample into RAM, thus for disk
217     * streaming. All this methods needs to know to proceed with streaming
218     * for the next time you call this method is stored in \a pPlaybackState.
219     * You have to allocate and initialize the playback_state_t structure by
220     * yourself before you use it to stream a sample:
221     * @code
222     * PlaybackState playbackstate;
223     * playbackstate.position = 0;
224     * playbackstate.reverse = false;
225     * playbackstate.loop_cycles_left = pSample->LoopPlayCount;
226     * @endcode
227     * You don't have to take care of things like if there is actually a loop
228     * defined or if the current read position is located within a loop area.
229     * The method already handles such cases by itself.
230     *
231     * @param pBuffer destination buffer
232     * @param FrameCount number of sample points to read
233     * @param pPlaybackState will be used to store and reload the playback
234     * state for the next ReadAndLoop() call
235     * @returns number of successfully read sample points
236     */
237     unsigned long Sample::ReadAndLoop (
238     void* pBuffer,
239     unsigned long FrameCount,
240 iliev 2020 PlaybackState* pPlaybackState,
241     Region* pRegion
242 iliev 2016 ) {
243 iliev 2020 // TODO: startAddrsCoarseOffset, endAddrsCoarseOffset
244     unsigned long samplestoread = FrameCount, totalreadsamples = 0, readsamples, samplestoloopend;
245     uint8_t* pDst = (uint8_t*) pBuffer;
246 iliev 2016 SetPos(pPlaybackState->position);
247 iliev 2020 if (pRegion->HasLoop) {
248     do {
249     samplestoloopend = pRegion->LoopEnd - GetPos();
250     readsamples = Read(&pDst[totalreadsamples * GetFrameSize()], Min(samplestoread, samplestoloopend));
251     samplestoread -= readsamples;
252     totalreadsamples += readsamples;
253     if (readsamples == samplestoloopend) {
254     SetPos(pRegion->LoopStart);
255     }
256     } while (samplestoread && readsamples);
257     } else {
258     totalreadsamples = Read(pBuffer, FrameCount);
259     }
260    
261 iliev 2016 pPlaybackState->position = GetPos();
262 iliev 2020
263     return totalreadsamples;
264 iliev 2016 }
265    
266     Region::Region() {
267     pSample = NULL;
268     pInstrument = NULL;
269 iliev 2026 pParentInstrument = NULL;
270 iliev 2016 loKey = hiKey = NONE;
271     minVel = maxVel = NONE;
272 iliev 2020 startAddrsOffset = startAddrsCoarseOffset = endAddrsOffset = endAddrsCoarseOffset = 0;
273     startloopAddrsOffset = startloopAddrsCoarseOffset = endloopAddrsOffset = endloopAddrsCoarseOffset = 0;
274     pan = fineTune = coarseTune = 0;
275     overridingRootKey = -1; // -1 means not used
276 iliev 2016
277 iliev 2020 HasLoop = false;
278     LoopStart = LoopEnd = 0;
279    
280 iliev 2026 EG1PreAttackDelay = EG1Attack = EG1Hold = EG1Decay = EG1Release = -12000;
281 iliev 2016 EG1Sustain = 0;
282 iliev 2026 EG2PreAttackDelay = EG2Attack = EG2Hold = EG2Decay = EG2Release = -12000;
283 iliev 2016 EG2Sustain = 0;
284 iliev 2026
285     modEnvToPitch = modLfoToPitch = modEnvToFilterFc = modLfoToFilterFc = modLfoToVolume = 0;
286     freqModLfo = 0;
287     delayModLfo = -12000;
288     vibLfoToPitch = 0;
289     freqVibLfo = 0;
290     delayVibLfo = -12000;
291    
292     exclusiveClass = 0;
293 iliev 2016 }
294    
295 iliev 2020 int Region::GetUnityNote() {
296     return overridingRootKey != -1 ? overridingRootKey : pSample->OriginalPitch;
297     }
298    
299 iliev 2016 void Region::SetGenerator(sf2::File* pFile, GenList& Gen) {
300     switch(Gen.GenOper) {
301     case START_ADDRS_OFFSET:
302     startAddrsOffset = Gen.GenAmount.wAmount;
303     break;
304     case END_ADDRS_OFFSET:
305     if (Gen.GenAmount.shAmount <= 0) {
306     endAddrsOffset = Gen.GenAmount.shAmount;
307     } else {
308     std::cerr << "Ignoring invalid endAddrsOffset" << std::endl;
309     }
310     break;
311     case STARTLOOP_ADDRS_OFFSET:
312     startloopAddrsOffset = Gen.GenAmount.shAmount;
313 iliev 2020 LoopStart += startloopAddrsOffset;
314 iliev 2016 break;
315     case ENDLOOP_ADDRS_OFFSET:
316     endloopAddrsOffset = Gen.GenAmount.shAmount;
317 iliev 2020 LoopEnd += endloopAddrsOffset;
318 iliev 2016 break;
319     case START_ADDRS_COARSE_OFFSET:
320     startAddrsCoarseOffset = Gen.GenAmount.wAmount;
321     break;
322     case MOD_LFO_TO_PITCH:
323 iliev 2026 modLfoToPitch = Gen.GenAmount.shAmount;
324 iliev 2016 break;
325     case VIB_LFO_TO_PITCH:
326 iliev 2026 vibLfoToPitch = Gen.GenAmount.shAmount;
327 iliev 2016 break;
328     case MOD_ENV_TO_PITCH:
329 iliev 2026 modEnvToPitch = Gen.GenAmount.shAmount;
330 iliev 2016 break;
331     case INITIAL_FILTER_FC:
332     break;
333     case INITIAL_FILTER_Q:
334     break;
335     case MOD_LFO_TO_FILTER_FC:
336 iliev 2026 modLfoToFilterFc = Gen.GenAmount.shAmount;
337 iliev 2016 break;
338     case MOD_ENV_TO_FILTER_FC:
339 iliev 2026 modEnvToFilterFc = Gen.GenAmount.shAmount;
340 iliev 2016 break;
341     case END_ADDRS_COARSE_OFFSET:
342 iliev 2020 endAddrsCoarseOffset = Gen.GenAmount.wAmount;
343 iliev 2016 break;
344     case MOD_LFO_TO_VOLUME:
345 iliev 2026 modLfoToVolume = Gen.GenAmount.shAmount;
346 iliev 2016 break;
347     case CHORUS_EFFECTS_SEND:
348     break;
349     case REVERB_EFFECTS_SEND:
350     break;
351     case PAN:
352     pan = Gen.GenAmount.shAmount;
353     pan * 64; pan /= 500;
354     if (pan < -64) pan = -64;
355     if (pan > 63) pan = 63;
356     break;
357     case DELAY_MOD_LFO:
358 iliev 2026 delayModLfo = Gen.GenAmount.shAmount;
359 iliev 2016 break;
360     case FREQ_MOD_LFO:
361 iliev 2026 freqModLfo = Gen.GenAmount.shAmount;
362 iliev 2016 break;
363     case DELAY_VIB_LFO:
364 iliev 2026 delayVibLfo = Gen.GenAmount.shAmount;
365 iliev 2016 break;
366     case FREQ_VIB_LFO:
367 iliev 2026 freqVibLfo = Gen.GenAmount.shAmount;
368 iliev 2016 break;
369     case DELAY_MOD_ENV:
370 iliev 2026 EG2PreAttackDelay = Gen.GenAmount.shAmount;
371 iliev 2016 break;
372     case ATTACK_MOD_ENV:
373 iliev 2026 EG2Attack = Gen.GenAmount.shAmount;
374 iliev 2016 break;
375     case HOLD_MOD_ENV:
376 iliev 2026 EG2Hold = Gen.GenAmount.shAmount;
377 iliev 2016 break;
378     case DECAY_MOD_ENV:
379 iliev 2026 EG2Decay = Gen.GenAmount.shAmount;
380 iliev 2016 break;
381     case SUSTAIN_MOD_ENV:
382 iliev 2026 EG2Sustain = Gen.GenAmount.shAmount;
383 iliev 2016 break;
384     case RELEASEMODENV:
385 iliev 2026 EG2Release = Gen.GenAmount.shAmount;
386 iliev 2016 break;
387     case KEYNUM_TO_MOD_ENV_HOLD:
388     break;
389     case KEYNUM_TO_MOD_ENV_DECAY:
390     break;
391     case DELAY_VOL_ENV:
392 iliev 2026 EG1PreAttackDelay = Gen.GenAmount.shAmount;
393 iliev 2016 break;
394     case ATTACK_VOL_ENV:
395 iliev 2026 EG1Attack = Gen.GenAmount.shAmount;
396 iliev 2016 break;
397     case HOLD_VOL_ENV:
398 iliev 2026 EG1Hold = Gen.GenAmount.shAmount;
399 iliev 2016 break;
400     case DECAY_VOL_ENV:
401 iliev 2026 EG1Decay = Gen.GenAmount.shAmount;
402 iliev 2016 break;
403     case SUSTAIN_VOL_ENV:
404 iliev 2026 EG1Sustain = Gen.GenAmount.shAmount;
405 iliev 2016 break;
406     case RELEASE_VOL_ENV:
407 iliev 2026 EG1Release = Gen.GenAmount.shAmount;
408 iliev 2016 break;
409     case KEYNUM_TO_VOL_ENV_HOLD:
410     break;
411     case KEYNUM_TO_VOL_ENV_DECAY:
412     break;
413     case INSTRUMENT: {
414     uint16_t id = Gen.GenAmount.wAmount;
415     if (id >= pFile->Instruments.size()) {
416     throw Exception("Broken SF2 file (missing instruments)");
417     }
418     pInstrument = pFile->Instruments[id];
419     break;
420     }
421     case KEY_RANGE:
422     loKey = Gen.GenAmount.ranges.byLo;
423     hiKey = Gen.GenAmount.ranges.byHi;
424     break;
425     case VEL_RANGE:
426     minVel = Gen.GenAmount.ranges.byLo;
427     maxVel = Gen.GenAmount.ranges.byHi;
428     break;
429     case STARTLOOP_ADDRS_COARSE_OFFSET:
430 iliev 2020 startloopAddrsCoarseOffset = Gen.GenAmount.wAmount;
431     LoopStart += startloopAddrsCoarseOffset * 32768;
432 iliev 2016 break;
433     case KEYNUM:
434     break;
435     case VELOCITY:
436     break;
437     case INITIAL_ATTENUATION:
438     break;
439     case ENDLOOP_ADDRS_COARSE_OFFSET:
440 iliev 2020 endloopAddrsCoarseOffset = Gen.GenAmount.wAmount;
441     LoopEnd += endloopAddrsCoarseOffset * 32768;
442 iliev 2016 break;
443     case COARSE_TUNE:
444 iliev 2020 coarseTune = Gen.GenAmount.shAmount;
445 iliev 2026 if (coarseTune < -120) coarseTune = -120;
446     if (coarseTune > 120) coarseTune = 120;
447 iliev 2016 break;
448     case FINE_TUNE:
449     fineTune = Gen.GenAmount.shAmount;
450     break;
451     case SAMPLE_ID: {
452     uint16_t sid = Gen.GenAmount.wAmount;
453     if (sid >= pFile->Samples.size()) {
454     throw Exception("Broken SF2 file (missing samples)");
455     }
456     pSample = pFile->Samples[sid];
457 iliev 2020
458     if (HasLoop) {
459     LoopStart += pSample->StartLoop;
460     LoopEnd += pSample->EndLoop;
461     if ( LoopStart < pSample->Start || LoopStart > pSample->End ||
462     LoopStart > LoopEnd || LoopEnd > pSample->End ) {
463     throw Exception("Broken SF2 file (invalid loops)");
464     }
465     LoopStart -= pSample->Start; // Relative to the sample start
466     LoopEnd -= pSample->Start; // Relative to the sample start
467     }
468 iliev 2016 break;
469     }
470     case SAMPLE_MODES:
471 iliev 2020 HasLoop = Gen.GenAmount.wAmount & 1;
472     // TODO: 3 indicates a sound which loops for the duration of key depression
473     // then proceeds to play the remainder of the sample.
474 iliev 2016 break;
475     case SCALE_TUNING:
476     break;
477     case EXCLUSIVE_CLASS:
478 iliev 2026 exclusiveClass = Gen.GenAmount.wAmount;
479 iliev 2016 break;
480     case OVERRIDING_ROOT_KEY:
481 iliev 2020 overridingRootKey = Gen.GenAmount.shAmount;
482 iliev 2016 break;
483     }
484     }
485    
486     void Region::SetModulator(sf2::File* pFile, ModList& Mod) {
487     modulators.push_back(ModulatorItem(Mod));
488     /*switch(srcType) {
489     case NO_CONTROLLER:
490     break;
491     case NOTE_ON_VELOCITY:
492     break;
493     case NOTE_ON_KEY_NUMBER:
494     break;
495     case POLY_PRESSURE:
496     break;
497     case CHANNEL_PRESSURE:
498     break;
499     case PITCH_WHEEL:
500     break;
501     case PITCH_WHEEL_SENSITIVITY:
502     break;
503     case LINK:
504     break;
505     default: std::cout << "Unknown controller source: " << srcType << std::endl;
506     }*/
507     }
508    
509 iliev 2026 int Region::GetPan(Region* pPresetRegion) {
510     if (pPresetRegion == NULL) return pan;
511     int p = pPresetRegion->pan + pan;
512     if (p < -64) p = -64;
513     if (p > 63) p = 63;
514     return p;
515     }
516    
517     int Region::GetFineTune(Region* pPresetRegion) {
518     if (pPresetRegion == NULL) return fineTune;
519     int t = pPresetRegion->fineTune + fineTune;
520     if (t < -99) t = -99;
521     if (t > 99) t = 99;
522     return t;
523     }
524    
525     int Region::GetCoarseTune(Region* pPresetRegion) {
526     if (pPresetRegion == NULL) return coarseTune;
527     int t = pPresetRegion->coarseTune + coarseTune;
528     if (t < -120) t = -120;
529     if (t > 120) t = 120;
530     return t;
531     }
532    
533     double Region::GetEG1PreAttackDelay(Region* pPresetRegion) {
534     if (pPresetRegion == NULL || pPresetRegion->EG1PreAttackDelay == NONE) return ToSeconds(EG1PreAttackDelay);
535     return ToSeconds(pPresetRegion->EG1PreAttackDelay + EG1PreAttackDelay);
536     }
537    
538     double Region::GetEG1Attack(Region* pPresetRegion) {
539     if (pPresetRegion == NULL || pPresetRegion->EG1Attack == NONE) return ToSeconds(EG1Attack);
540     return ToSeconds(pPresetRegion->EG1Attack + EG1Attack);
541     }
542    
543     double Region::GetEG1Hold(Region* pPresetRegion) {
544     if (pPresetRegion == NULL || pPresetRegion->EG1Hold == NONE) return ToSeconds(EG1Hold);
545     return ToSeconds(pPresetRegion->EG1Hold + EG1Hold);
546     }
547    
548     double Region::GetEG1Decay(Region* pPresetRegion) {
549     if (pPresetRegion == NULL || pPresetRegion->EG1Decay == NONE) return ToSeconds(EG1Decay);
550     return ToSeconds(pPresetRegion->EG1Decay + EG1Decay);
551     }
552    
553     double Region::GetEG1Sustain(Region* pPresetRegion) {
554     if (pPresetRegion == NULL || pPresetRegion->EG1Sustain == NONE) return ToPermilles(EG1Sustain);
555     return ToPermilles(pPresetRegion->EG1Sustain + EG1Sustain);
556     }
557    
558     double Region::GetEG1Release(Region* pPresetRegion) {
559     if (pPresetRegion == NULL || pPresetRegion->EG1Release == NONE) return ToSeconds(EG1Release);
560     return ToSeconds(pPresetRegion->EG1Release + EG1Release);
561     }
562    
563     double Region::GetEG2PreAttackDelay(Region* pPresetRegion) {
564     if (pPresetRegion == NULL || pPresetRegion->EG2PreAttackDelay == NONE) return ToSeconds(EG2PreAttackDelay);
565     return ToSeconds(pPresetRegion->EG2PreAttackDelay + EG2PreAttackDelay);
566     }
567    
568     double Region::GetEG2Attack(Region* pPresetRegion) {
569     if (pPresetRegion == NULL || pPresetRegion->EG2Attack == NONE) return ToSeconds(EG2Attack);
570     return ToSeconds(pPresetRegion->EG2Attack + EG2Attack);
571     }
572    
573     double Region::GetEG2Hold(Region* pPresetRegion) {
574     if (pPresetRegion == NULL || pPresetRegion->EG2Hold == NONE) return ToSeconds(EG2Hold);
575     return ToSeconds(pPresetRegion->EG2Hold + EG2Hold);
576     }
577    
578     double Region::GetEG2Decay(Region* pPresetRegion) {
579     if (pPresetRegion == NULL || pPresetRegion->EG2Decay == NONE) return ToSeconds(EG2Decay);
580     return ToSeconds(pPresetRegion->EG2Decay + EG2Decay);
581     }
582    
583     double Region::GetEG2Sustain(Region* pPresetRegion) {
584     if (pPresetRegion == NULL || pPresetRegion->EG2Sustain == NONE) {
585     return EG2Sustain == NONE ? NONE : 1000 - EG2Sustain;
586     }
587     return 1000 - (pPresetRegion->EG2Sustain + EG2Sustain);
588     }
589    
590     double Region::GetEG2Release(Region* pPresetRegion) {
591     if (pPresetRegion == NULL || pPresetRegion->EG2Release == NONE) return ToSeconds(EG2Release);
592     return ToSeconds(pPresetRegion->EG2Release + EG2Release);
593     }
594    
595     int Region::GetModEnvToPitch(Region* pPresetRegion) {
596     return modEnvToPitch + (pPresetRegion ? pPresetRegion->modEnvToPitch : 0);
597     }
598    
599     int Region::GetModLfoToPitch(Region* pPresetRegion) {
600     return modLfoToPitch + (pPresetRegion ? pPresetRegion->modLfoToPitch : 0);
601     }
602    
603     int Region::GetModEnvToFilterFc(Region* pPresetRegion) {
604     return modEnvToFilterFc + (pPresetRegion ? pPresetRegion->modEnvToFilterFc : 0);
605     }
606    
607     int Region::GetModLfoToFilterFc(Region* pPresetRegion) {
608     return modLfoToFilterFc + (pPresetRegion ? pPresetRegion->modLfoToFilterFc : 0);
609     }
610    
611     double Region::GetModLfoToVolume(Region* pPresetRegion) {
612     return ToPermilles(modLfoToVolume + (pPresetRegion ? pPresetRegion->modLfoToVolume : 0));
613     }
614    
615     double Region::GetFreqModLfo(Region* pPresetRegion) {
616     if (pPresetRegion == NULL || pPresetRegion->freqModLfo == NONE) return ToHz(freqModLfo);
617     return ToHz(pPresetRegion->freqModLfo + freqModLfo);
618     }
619    
620     double Region::GetDelayModLfo(Region* pPresetRegion) {
621     if (pPresetRegion == NULL || pPresetRegion->delayModLfo == NONE) return ToSeconds(delayModLfo);
622     return ToSeconds(pPresetRegion->delayModLfo + delayModLfo);
623     }
624    
625     int Region::GetVibLfoToPitch(Region* pPresetRegion) {
626     return vibLfoToPitch + (pPresetRegion ? pPresetRegion->vibLfoToPitch : 0);
627     }
628    
629     double Region::GetFreqVibLfo(Region* pPresetRegion) {
630     if (pPresetRegion == NULL || pPresetRegion->freqVibLfo == NONE) return ToHz(freqVibLfo);
631     return ToHz(pPresetRegion->freqVibLfo + freqVibLfo);
632     }
633    
634     double Region::GetDelayVibLfo(Region* pPresetRegion) {
635     if (pPresetRegion == NULL || pPresetRegion->delayVibLfo == NONE) return ToSeconds(delayVibLfo);
636     return ToSeconds(pPresetRegion->delayVibLfo + delayVibLfo);
637     }
638    
639 iliev 2016 InstrumentBase::InstrumentBase(sf2::File* pFile) {
640     this->pFile = pFile;
641     pGlobalRegion = NULL;
642     }
643    
644     InstrumentBase::~InstrumentBase() {
645     if (pGlobalRegion) delete pGlobalRegion;
646     for (int i = regions.size() - 1; i >= 0; i--) {
647     if (regions[i]) delete (regions[i]);
648     }
649     }
650    
651     int InstrumentBase::GetRegionCount() {
652 iliev 2020 return regions.size();
653 iliev 2016 }
654    
655     Region* InstrumentBase::GetRegion(int idx) {
656     if (idx < 0 || idx >= GetRegionCount()) {
657     throw Exception("Region index out of bounds");
658     }
659    
660     return regions[idx];
661     }
662    
663     std::vector<Region*> InstrumentBase::GetRegionsOnKey(int key, uint8_t vel) {
664     std::vector<Region*> v;
665     for (int i = 0; i < GetRegionCount(); i++) {
666     Region* r = GetRegion(i);
667     if (
668 iliev 2026 ((r->loKey == NONE && r->hiKey == NONE) || (key >= r->loKey && key <= r->hiKey)) &&
669 iliev 2016 ((r->minVel == NONE && r->maxVel == NONE) || (vel >= r->minVel && vel <= r->maxVel))
670     ) {
671     v.push_back(r);
672     }
673     }
674    
675     return v;
676     }
677    
678     Instrument::Instrument(sf2::File* pFile, RIFF::Chunk* ck) : InstrumentBase(pFile) {
679     this->pFile = pFile;
680     LoadString(ck, Name, 20);
681     InstBagNdx = ck->ReadInt16();
682     }
683    
684     Instrument::~Instrument() {
685    
686     }
687    
688 iliev 2020 Region* Instrument::CreateRegion() {
689     Region* r = new Region;
690 iliev 2026 r->pParentInstrument = this;
691    
692 iliev 2020 if (pGlobalRegion != NULL) {
693     r->loKey = pGlobalRegion->loKey;
694     r->hiKey = pGlobalRegion->hiKey;
695     r->minVel = pGlobalRegion->minVel;
696     r->maxVel = pGlobalRegion->maxVel;
697     r->pan = pGlobalRegion->pan;
698     r->fineTune = pGlobalRegion->fineTune;
699     r->coarseTune = pGlobalRegion->coarseTune;
700     r->overridingRootKey = pGlobalRegion->overridingRootKey;
701     r->startAddrsOffset = pGlobalRegion->startAddrsOffset;
702     r->startAddrsCoarseOffset = pGlobalRegion->startAddrsCoarseOffset;
703     r->endAddrsOffset = pGlobalRegion->endAddrsOffset;
704     r->endAddrsCoarseOffset = pGlobalRegion->endAddrsCoarseOffset;
705     r->startloopAddrsOffset = pGlobalRegion->startloopAddrsOffset;
706     r->startloopAddrsCoarseOffset = pGlobalRegion->startloopAddrsCoarseOffset;
707     r->endloopAddrsOffset = pGlobalRegion->endloopAddrsOffset;
708     r->endloopAddrsCoarseOffset = pGlobalRegion->endloopAddrsCoarseOffset;
709    
710     r->EG1PreAttackDelay = pGlobalRegion->EG1PreAttackDelay;
711     r->EG1Attack = pGlobalRegion->EG1Attack;
712     r->EG1Hold = pGlobalRegion->EG1Hold;
713     r->EG1Decay = pGlobalRegion->EG1Decay;
714     r->EG1Sustain = pGlobalRegion->EG1Sustain;
715     r->EG1Release = pGlobalRegion->EG1Release;
716    
717     r->EG2PreAttackDelay = pGlobalRegion->EG2PreAttackDelay;
718     r->EG2Attack = pGlobalRegion->EG2Attack;
719     r->EG2Hold = pGlobalRegion->EG2Hold;
720     r->EG2Decay = pGlobalRegion->EG2Decay;
721     r->EG2Sustain = pGlobalRegion->EG2Sustain;
722     r->EG2Release = pGlobalRegion->EG2Release;
723    
724 iliev 2026 r->modEnvToPitch = pGlobalRegion->modEnvToPitch;
725     r->modLfoToPitch = pGlobalRegion->modLfoToPitch;
726     r->modEnvToFilterFc = pGlobalRegion->modEnvToFilterFc;
727     r->modLfoToFilterFc = pGlobalRegion->modLfoToFilterFc;
728     r->modLfoToVolume = pGlobalRegion->modLfoToVolume;
729     r->freqModLfo = pGlobalRegion->freqModLfo;
730     r->delayModLfo = pGlobalRegion->delayModLfo;
731     r->vibLfoToPitch = pGlobalRegion->vibLfoToPitch;
732     r->freqVibLfo = pGlobalRegion->freqVibLfo;
733     r->delayVibLfo = pGlobalRegion->delayVibLfo;
734    
735 iliev 2020 r->HasLoop = pGlobalRegion->HasLoop;
736     r->LoopStart = pGlobalRegion->LoopStart;
737     r->LoopEnd = pGlobalRegion->LoopEnd;
738 iliev 2026
739     r->exclusiveClass = pGlobalRegion->exclusiveClass;
740 iliev 2020 }
741    
742     return r;
743     }
744    
745     void Instrument::DeleteRegion(Region* pRegion) {
746     for (int i = 0; i < regions.size(); i++) {
747     if (regions[i] == pRegion) {
748     delete pRegion;
749     regions[i] = NULL;
750     return;
751     }
752     }
753    
754     std::cerr << "Can't remove unknown Region" << std::endl;
755     }
756    
757 iliev 2016 void Instrument::LoadRegions(int idx1, int idx2) {
758 iliev 2020 for (int i = idx1; i < idx2; i++) {
759 iliev 2016 int gIdx1 = pFile->InstBags[i].InstGenNdx;
760     int gIdx2 = pFile->InstBags[i + 1].InstGenNdx;
761    
762     if (gIdx1 < 0 || gIdx2 < 0 || gIdx1 > gIdx2 || gIdx2 >= pFile->InstGenLists.size()) {
763     throw Exception("Broken SF2 file (invalid InstGenNdx)");
764     }
765    
766     int mIdx1 = pFile->InstBags[i].InstModNdx;
767     int mIdx2 = pFile->InstBags[i + 1].InstModNdx;
768    
769     if (mIdx1 < 0 || mIdx2 < 0 || mIdx1 > mIdx2 || mIdx2 >= pFile->InstModLists.size()) {
770     throw Exception("Broken SF2 file (invalid InstModNdx)");
771     }
772    
773 iliev 2020 Region* reg = CreateRegion();
774 iliev 2016
775     for (int j = gIdx1; j < gIdx2; j++) {
776     reg->SetGenerator(pFile, pFile->InstGenLists[j]);
777     // TODO: ignore generators following a sampleID generator
778     }
779    
780     for (int j = mIdx1; j < mIdx2; j++) {
781     reg->SetModulator(pFile, pFile->InstModLists[j]);
782     }
783    
784     if (reg->pSample == NULL) {
785 iliev 2020 if (i == idx1 && idx2 - idx1 > 1) {
786 iliev 2016 pGlobalRegion = reg; // global zone
787     } else {
788     std::cerr << "Ignoring instrument's region without sample" << std::endl;
789     delete reg;
790     }
791     } else {
792     regions.push_back(reg);
793     }
794     }
795     }
796    
797     Preset::Preset(sf2::File* pFile, RIFF::Chunk* ck): InstrumentBase(pFile) {
798     this->pFile = pFile;
799     LoadString(ck, Name, 20);
800     PresetNum = ck->ReadInt16();
801     Bank = ck->ReadInt16();
802     PresetBagNdx = ck->ReadInt16();
803     Library = ck->ReadInt32();
804     Genre = ck->ReadInt32();
805     Morphology = ck->ReadInt32();
806     }
807    
808     Preset::~Preset() {
809    
810     }
811    
812 iliev 2026 Region* Preset::CreateRegion() {
813     Region* r = new Region;
814    
815     r->EG1PreAttackDelay = r->EG1Attack = r->EG1Hold = r->EG1Decay = r->EG1Sustain = r->EG1Release = NONE;
816     r->EG2PreAttackDelay = r->EG2Attack = r->EG2Hold = r->EG2Decay = r->EG2Sustain = r->EG2Release = NONE;
817     r->freqModLfo = r->delayModLfo = r->freqVibLfo = r->delayVibLfo = NONE;
818    
819     if (pGlobalRegion != NULL) {
820     r->pan = pGlobalRegion->pan;
821     r->fineTune = pGlobalRegion->fineTune;
822     r->coarseTune = pGlobalRegion->coarseTune;
823    
824     r->EG1PreAttackDelay = pGlobalRegion->EG1PreAttackDelay;
825     r->EG1Attack = pGlobalRegion->EG1Attack;
826     r->EG1Hold = pGlobalRegion->EG1Hold;
827     r->EG1Decay = pGlobalRegion->EG1Decay;
828     r->EG1Sustain = pGlobalRegion->EG1Sustain;
829     r->EG1Release = pGlobalRegion->EG1Release;
830    
831     r->EG2PreAttackDelay = pGlobalRegion->EG2PreAttackDelay;
832     r->EG2Attack = pGlobalRegion->EG2Attack;
833     r->EG2Hold = pGlobalRegion->EG2Hold;
834     r->EG2Decay = pGlobalRegion->EG2Decay;
835     r->EG2Sustain = pGlobalRegion->EG2Sustain;
836     r->EG2Release = pGlobalRegion->EG2Release;
837    
838     r->modEnvToPitch = pGlobalRegion->modEnvToPitch;
839     r->modLfoToPitch = pGlobalRegion->modLfoToPitch;
840     r->modEnvToFilterFc = pGlobalRegion->modEnvToFilterFc;
841     r->modLfoToFilterFc = pGlobalRegion->modLfoToFilterFc;
842     r->modLfoToVolume = pGlobalRegion->modLfoToVolume;
843     r->freqModLfo = pGlobalRegion->freqModLfo;
844     r->delayModLfo = pGlobalRegion->delayModLfo;
845     r->vibLfoToPitch = pGlobalRegion->vibLfoToPitch;
846     r->freqVibLfo = pGlobalRegion->freqVibLfo;
847     r->delayVibLfo = pGlobalRegion->delayVibLfo;
848     }
849    
850     return r;
851     }
852    
853 iliev 2016 void Preset::LoadRegions(int idx1, int idx2) {
854 iliev 2020 for (int i = idx1; i < idx2; i++) {
855 iliev 2016 int gIdx1 = pFile->PresetBags[i].GenNdx;
856     int gIdx2 = pFile->PresetBags[i + 1].GenNdx;
857    
858     if (gIdx1 < 0 || gIdx2 < 0 || gIdx1 > gIdx2 || gIdx2 >= pFile->PresetGenLists.size()) {
859     throw Exception("Broken SF2 file (invalid PresetGenNdx)");
860     }
861    
862 iliev 2026 Region* reg = CreateRegion();
863 iliev 2016
864     for (int j = gIdx1; j < gIdx2; j++) {
865     reg->SetGenerator(pFile, pFile->PresetGenLists[j]);
866     }
867     if (reg->pInstrument == NULL) {
868 iliev 2020 if (i == idx1 && idx2 - idx1 > 1) {
869 iliev 2016 pGlobalRegion = reg; // global zone
870     } else {
871     std::cerr << "Ignoring preset's region without instrument" << std::endl;
872     delete reg;
873     }
874     } else {
875     regions.push_back(reg);
876     }
877     }
878     }
879    
880     /** @brief Constructor.
881     *
882     * Load an existing SF2 file.
883     *
884     * @param pRIFF - pointer to a RIFF file which is actually the SF2 file
885     * to load
886     * @throws Exception if given file is not a SF2 file, expected chunks
887     * are missing
888     */
889     File::File(RIFF::File* pRIFF) {
890     if (!pRIFF) throw Exception("NULL pointer reference to RIFF::File object.");
891     this->pRIFF = pRIFF;
892    
893     if (pRIFF->GetListType() != RIFF_TYPE_SF2) {
894     throw Exception("Not a SF2 file");
895     }
896    
897     pInfo = new Info(pRIFF);
898     if (pInfo->pVer->Major != 2) {
899     throw Exception("Unsupported version: " + ToString(pInfo->pVer->Major));
900     }
901    
902     RIFF::List* lstSDTA = pRIFF->GetSubList(LIST_TYPE_SDTA);
903     if (lstSDTA == NULL) {
904     throw Exception("Broken SF2 file (missing sdta)");
905     }
906    
907     RIFF::Chunk* pCkSmpl = lstSDTA->GetSubChunk(CHUNK_ID_SMPL);
908     RIFF::Chunk* pCkSm24 = lstSDTA->GetSubChunk(CHUNK_ID_SM24);
909     if (pCkSmpl != NULL && pCkSm24 != NULL) {
910     long l = pCkSmpl->GetSize() / 2;
911     if (l%2) l++;
912     if (pCkSm24->GetSize() != l) {
913     pCkSm24 = NULL; // ignoring sm24 due to invalid size
914     }
915     }
916    
917     RIFF::List* lstPDTA = pRIFF->GetSubList(LIST_TYPE_PDTA);
918     if (lstPDTA == NULL) {
919     throw Exception("Broken SF2 file (missing pdta)");
920     }
921    
922     RIFF::Chunk* ck = lstPDTA->GetSubChunk(CHUNK_ID_PHDR);
923     if (ck->GetSize() < 38) {
924     throw Exception("Broken SF2 file (broken phdr)");
925     }
926    
927     int count = ck->GetSize() / 38;
928     for (int i = 0; i < count; i++) {
929     Presets.push_back(new Preset(this, ck));
930     }
931    
932     ck = GetMandatoryChunk(lstPDTA, CHUNK_ID_PBAG);
933     if (ck->GetSize() < 4 || (ck->GetSize() % 4)) {
934     throw Exception("Broken SF2 file (broken pbag)");
935     }
936    
937     count = ck->GetSize() / 4;
938     for (int i = 0; i < count; i++) {
939     PresetBag pb;
940     pb.GenNdx = ck->ReadInt16();
941     pb.ModNdx = ck->ReadInt16();
942     PresetBags.push_back(pb);
943     }
944     //std::cout << "Preset bags: " << PresetBags.size() << std::endl;
945    
946     ck = GetMandatoryChunk(lstPDTA, CHUNK_ID_PMOD);
947     if (ck->GetSize() % 10) {
948     throw Exception("Broken SF2 file (broken pmod)");
949     }
950    
951     count = ck->GetSize() / 10;
952     for (int i = 0; i < count; i++) {
953     ModList ml;
954     ml.ModSrcOper = ck->ReadInt16();
955     ml.ModDestOper = ck->ReadInt16();
956     ml.ModAmount = ck->ReadInt16();
957     ml.ModAmtSrcOper = ck->ReadInt16();
958     ml.ModTransOper = ck->ReadInt16();
959     PresetModLists.push_back(ml);
960     }
961     //std::cout << "Preset mod lists: " << PresetModLists.size() << std::endl;
962    
963     ck = GetMandatoryChunk(lstPDTA, CHUNK_ID_PGEN);
964     if (ck->GetSize() < 4 || (ck->GetSize() % 4)) {
965     throw Exception("Broken SF2 file (broken pgen)");
966     }
967    
968     count = ck->GetSize() / 4;
969     for (int i = 0; i < count; i++) {
970     GenList gl;
971     gl.GenOper = ck->ReadInt16();
972     gl.GenAmount.wAmount = ck->ReadInt16();
973     PresetGenLists.push_back(gl);
974     }
975     //std::cout << "Preset gen lists: " << PresetGenLists.size() << std::endl;
976    
977     ck = GetMandatoryChunk(lstPDTA, CHUNK_ID_INST);
978     if (ck->GetSize() < (22 * 2) || (ck->GetSize() % 22)) {
979     throw Exception("Broken SF2 file (broken inst)");
980     }
981     count = ck->GetSize() / 22;
982     for (int i = 0; i < count; i++) {
983     Instruments.push_back(new Instrument(this, ck));
984     }
985    
986     ck = GetMandatoryChunk(lstPDTA, CHUNK_ID_IBAG);
987     if (ck->GetSize() < 4 || (ck->GetSize() % 4)) {
988     throw Exception("Broken SF2 file (broken ibag)");
989     }
990    
991     count = ck->GetSize() / 4;
992     for (int i = 0; i < count; i++) {
993     InstBag ib;
994     ib.InstGenNdx = ck->ReadInt16();
995     ib.InstModNdx = ck->ReadInt16();
996     InstBags.push_back(ib);
997     }
998     //std::cout << "Instrument bags: " << InstBags.size() << std::endl;
999    
1000     ck = GetMandatoryChunk(lstPDTA, CHUNK_ID_IMOD);
1001     if (ck->GetSize() % 10) {
1002     throw Exception("Broken SF2 file (broken imod)");
1003     }
1004    
1005     count = ck->GetSize() / 10;
1006     for (int i = 0; i < count; i++) {
1007     ModList ml;
1008     ml.ModSrcOper = ck->ReadInt16();
1009     ml.ModDestOper = ck->ReadInt16();
1010     ml.ModAmount = ck->ReadInt16();
1011     ml.ModAmtSrcOper = ck->ReadInt16();
1012     ml.ModTransOper = ck->ReadInt16();
1013     InstModLists.push_back(ml);
1014     }
1015     //std::cout << "Instrument mod lists: " << InstModLists.size() << std::endl;
1016    
1017     ck = GetMandatoryChunk(lstPDTA, CHUNK_ID_IGEN);
1018     if (ck->GetSize() < 4 || (ck->GetSize() % 4)) {
1019     throw Exception("Broken SF2 file (broken igen)");
1020     }
1021    
1022     count = ck->GetSize() / 4;
1023     for (int i = 0; i < count; i++) {
1024     GenList gl;
1025     gl.GenOper = ck->ReadInt16();
1026     gl.GenAmount.wAmount = ck->ReadInt16();
1027     InstGenLists.push_back(gl);
1028     }
1029     //std::cout << "Instrument gen lists: " << InstGenLists.size() << std::endl;
1030    
1031     ck = GetMandatoryChunk(lstPDTA, CHUNK_ID_SHDR);
1032     if ((ck->GetSize() % 46)) {
1033     throw Exception("Broken SF2 file (broken shdr)");
1034     }
1035     count = ck->GetSize() / 46;
1036     for (int i = 0; i < count; i++) {
1037     Samples.push_back(new Sample(ck, pCkSmpl, pCkSm24));
1038     }
1039    
1040     // Loading instrument regions
1041     for (int i = 0; i < Instruments.size() - 1; i++) {
1042     Instrument* instr = Instruments[i];
1043     int x1 = instr->InstBagNdx;
1044     int x2 = Instruments[i + 1]->InstBagNdx;
1045     if (x1 < 0 || x2 < 0 || x1 > x2 || x2 >= InstBags.size()) {
1046     throw Exception("Broken SF2 file (invalid InstBagNdx)");
1047     }
1048    
1049     instr->LoadRegions(x1, x2);
1050     }
1051    
1052     // Loading preset regions
1053     for (int i = 0; i < Presets.size() - 1; i++) {
1054     Preset* preset = Presets[i];
1055     int x1 = preset->PresetBagNdx;
1056     int x2 = Presets[i + 1]->PresetBagNdx;
1057     if (x1 < 0 || x2 < 0 || x1 > x2 || x2 >= PresetBags.size()) {
1058     throw Exception("Broken SF2 file (invalid PresetBagNdx)");
1059     }
1060    
1061     preset->LoadRegions(x1, x2);
1062     }
1063     }
1064    
1065     File::~File() {
1066     delete pInfo;
1067     for (int i = Presets.size() - 1; i >= 0; i--) {
1068     if (Presets[i]) delete (Presets[i]);
1069     }
1070     for (int i = Instruments.size() - 1; i >= 0; i--) {
1071     if (Instruments[i]) delete (Instruments[i]);
1072     }
1073     for (int i = Samples.size() - 1; i >= 0; i--) {
1074     if (Samples[i]) delete (Samples[i]);
1075     }
1076     }
1077    
1078     int File::GetPresetCount() {
1079     return Presets.size() - 1; // exclude terminal preset (EOP)
1080     }
1081    
1082     Preset* File::GetPreset(int idx) {
1083     if (idx < 0 || idx >= GetPresetCount()) {
1084     throw Exception("Preset index out of bounds");
1085     }
1086    
1087     return Presets[idx];
1088     }
1089    
1090     int File::GetInstrumentCount() {
1091     return Instruments.size() - 1; // exclude terminal instrument (EOI)
1092     }
1093    
1094     Instrument* File::GetInstrument(int idx) {
1095     if (idx < 0 || idx >= GetInstrumentCount()) {
1096     throw Exception("Instrument index out of bounds");
1097     }
1098    
1099     return Instruments[idx];
1100     }
1101    
1102 iliev 2020 void File::DeleteInstrument(Instrument* pInstrument) {
1103     for (int i = 0; i < GetPresetCount(); i++) {
1104     Preset* p = GetPreset(i);
1105     if (p == NULL) continue;
1106     for (int j = p->GetRegionCount() - 1; j >= 0 ; j--) {
1107     if (p->GetRegion(j) && p->GetRegion(j)->pInstrument == pInstrument) {
1108     p->GetRegion(j)->pInstrument = NULL;
1109     }
1110     }
1111     }
1112    
1113     for (int i = 0; i < GetInstrumentCount(); i++) {
1114     if (GetInstrument(i) == pInstrument) {
1115     Instruments[i] = NULL;
1116     delete pInstrument;
1117     }
1118     }
1119     }
1120    
1121 iliev 2016 int File::GetSampleCount() {
1122     return Samples.size() - 1; // exclude terminal sample (EOS)
1123     }
1124    
1125     Sample* File::GetSample(int idx) {
1126     if (idx < 0 || idx >= GetSampleCount()) {
1127     throw Exception("Sample index out of bounds");
1128     }
1129    
1130     return Samples[idx];
1131     }
1132    
1133     void File::DeleteSample(Sample* pSample) {
1134 iliev 2020 // Sanity check
1135     for (int i = GetInstrumentCount() - 1; i >= 0; i--) {
1136     Instrument* pInstr = GetInstrument(i);
1137     if (pInstr == NULL) continue;
1138    
1139     for (int j = pInstr->GetRegionCount() - 1; j >= 0 ; j--) {
1140     if (pInstr->GetRegion(j) && pInstr->GetRegion(j)->GetSample() == pSample) {
1141     std::cerr << "Deleting sample which is still in use" << std::endl;
1142     }
1143     }
1144     }
1145     ///////
1146    
1147 iliev 2016 for (int i = 0; i < GetSampleCount(); i++) {
1148     if (Samples[i] == pSample) {
1149     delete pSample;
1150     Samples[i] = NULL;
1151     return;
1152     }
1153     }
1154    
1155     throw Exception("Unknown sample: " + pSample->Name);
1156     }
1157    
1158     bool File::HasSamples() {
1159     for (int i = 0; i < GetSampleCount(); i++) {
1160     if (Samples[i] != NULL) return true;
1161     }
1162    
1163     return false;
1164     }
1165    
1166     /**
1167     * Loads the whole sample wave into RAM. Use
1168     * ReleaseSampleData() to free the memory if you don't need the cached
1169     * sample data anymore.
1170     *
1171     * @returns buffer_t structure with start address and size of the buffer
1172     * in bytes
1173     * @see ReleaseSampleData(), Read(), SetPos()
1174     */
1175     Sample::buffer_t Sample::LoadSampleData() {
1176     return LoadSampleDataWithNullSamplesExtension(GetTotalFrameCount(), 0); // 0 amount of NullSamples
1177     }
1178    
1179     /**
1180     * Reads and caches the first \a SampleCount
1181     * numbers of SamplePoints in RAM. Use ReleaseSampleData() to free the
1182     * memory space if you don't need the cached samples anymore.
1183     * Read the <i>Size</i> member of the <i>buffer_t</i> structure
1184     * that will be returned to determine the actual cached samples, but note
1185     * that the size is given in bytes! You get the number of actually cached
1186     * samples by dividing it by the frame size of the sample:
1187     * @code
1188     * buffer_t buf = pSample->LoadSampleData(acquired_samples);
1189     * long cachedsamples = buf.Size / pSample->FrameSize;
1190     * @endcode
1191     *
1192     * @param SampleCount - number of sample points to load into RAM
1193     * @returns buffer_t structure with start address and size of
1194     * the cached sample data in bytes
1195     * @see ReleaseSampleData(), Read(), SetPos()
1196     */
1197     Sample::buffer_t Sample::LoadSampleData(unsigned long SampleCount) {
1198     return LoadSampleDataWithNullSamplesExtension(SampleCount, 0); // 0 amount of NullSamples
1199     }
1200    
1201     /**
1202     * Loads the whole sample wave into RAM. Use
1203     * ReleaseSampleData() to free the memory if you don't need the cached
1204     * sample data anymore.
1205     * The method will add \a NullSamplesCount silence samples past the
1206     * official buffer end (this won't affect the 'Size' member of the
1207     * buffer_t structure, that means 'Size' always reflects the size of the
1208     * actual sample data, the buffer might be bigger though). Silence
1209     * samples past the official buffer are needed for differential
1210     * algorithms that always have to take subsequent samples into account
1211     * (resampling/interpolation would be an important example) and avoids
1212     * memory access faults in such cases.
1213     *
1214     * @param NullSamplesCount - number of silence samples the buffer should
1215     * be extended past it's data end
1216     * @returns buffer_t structure with start address and
1217     * size of the buffer in bytes
1218     * @see ReleaseSampleData(), Read(), SetPos()
1219     */
1220     Sample::buffer_t Sample::LoadSampleDataWithNullSamplesExtension(uint NullSamplesCount) {
1221     return LoadSampleDataWithNullSamplesExtension(GetTotalFrameCount(), NullSamplesCount);
1222     }
1223    
1224     /**
1225     * Reads and caches the first \a SampleCount
1226     * numbers of SamplePoints in RAM. Use ReleaseSampleData() to free the
1227     * memory space if you don't need the cached samples anymore.
1228     * Read the <i>Size</i> member of the <i>buffer_t</i> structure
1229     * that will be returned to determine the actual cached samples, but note
1230     * that the size is given in bytes! You get the number of actually cached
1231     * samples by dividing it by the frame size of the sample:
1232     * @code
1233     * buffer_t buf = pSample->LoadSampleDataWithNullSamplesExtension(acquired_samples, null_samples);
1234     * long cachedsamples = buf.Size / pSample->FrameSize;
1235     * @endcode
1236     * The method will add \a NullSamplesCount silence samples past the
1237     * official buffer end (this won't affect the 'Size' member of the
1238     * buffer_t structure, that means 'Size' always reflects the size of the
1239     * actual sample data, the buffer might be bigger though). Silence
1240     * samples past the official buffer are needed for differential
1241     * algorithms that always have to take subsequent samples into account
1242     * (resampling/interpolation would be an important example) and avoids
1243     * memory access faults in such cases.
1244     *
1245     * @param SampleCount - number of sample points to load into RAM
1246     * @param NullSamplesCount - number of silence samples the buffer should
1247     * be extended past it's data end
1248     * @returns buffer_t structure with start address and
1249     * size of the cached sample data in bytes
1250     * @see ReleaseSampleData(), Read(), SetPos()
1251     */
1252     Sample::buffer_t Sample::LoadSampleDataWithNullSamplesExtension(unsigned long SampleCount, uint NullSamplesCount) {
1253     if (SampleCount > GetTotalFrameCount()) SampleCount = GetTotalFrameCount();
1254     if (RAMCache.pStart) delete[] (int8_t*) RAMCache.pStart;
1255     unsigned long allocationsize = (SampleCount + NullSamplesCount) * GetFrameSize();
1256     SetPos(0); // reset read position to begin of sample
1257     RAMCache.pStart = new int8_t[allocationsize];
1258     RAMCache.Size = Read(RAMCache.pStart, SampleCount) * GetFrameSize();
1259     RAMCache.NullExtensionSize = allocationsize - RAMCache.Size;
1260     // fill the remaining buffer space with silence samples
1261     memset((int8_t*)RAMCache.pStart + RAMCache.Size, 0, RAMCache.NullExtensionSize);
1262     return GetCache();
1263     }
1264    
1265     /**
1266     * Returns current cached sample points. A buffer_t structure will be
1267     * returned which contains address pointer to the begin of the cache and
1268     * the size of the cached sample data in bytes. Use
1269     * <i>LoadSampleData()</i> to cache a specific amount of sample points in
1270     * RAM.
1271     *
1272     * @returns buffer_t structure with current cached sample points
1273     * @see LoadSampleData();
1274     */
1275     Sample::buffer_t Sample::GetCache() {
1276     // return a copy of the buffer_t structure
1277     buffer_t result;
1278     result.Size = this->RAMCache.Size;
1279     result.pStart = this->RAMCache.pStart;
1280     result.NullExtensionSize = this->RAMCache.NullExtensionSize;
1281     return result;
1282     }
1283    
1284     /**
1285     * Frees the cached sample from RAM if loaded with
1286     * <i>LoadSampleData()</i> previously.
1287     *
1288     * @see LoadSampleData();
1289     */
1290     void Sample::ReleaseSampleData() {
1291     if (RAMCache.pStart) delete[] (int8_t*) RAMCache.pStart;
1292     RAMCache.pStart = NULL;
1293     RAMCache.Size = 0;
1294     RAMCache.NullExtensionSize = 0;
1295     }
1296    
1297     /**
1298     * Sets the position within the sample (in sample points, not in
1299     * bytes). Use this method and <i>Read()</i> if you don't want to load
1300     * the sample into RAM, thus for disk streaming.
1301     *
1302     * @param SampleCount number of sample points to jump
1303     * @returns the new sample position
1304     * @see Read()
1305     */
1306     unsigned long Sample::SetPos(unsigned long SampleCount) {
1307     pCkSmpl->SetPos((Start * 2) + (SampleCount * 2), RIFF::stream_start);
1308     if(pCkSm24) pCkSm24->SetPos(Start + SampleCount, RIFF::stream_start);
1309     return SampleCount;
1310     }
1311    
1312     /**
1313     * Returns the current position in the sample (in sample points).
1314     */
1315     unsigned long Sample::GetPos() {
1316     return (pCkSmpl->GetPos() - (Start * 2)) / 2;
1317     }
1318    
1319     /**
1320     * Reads \a SampleCount number of sample points from the current
1321     * position into the buffer pointed by \a pBuffer and increments the
1322     * position within the sample. Use this method
1323     * and <i>SetPos()</i> if you don't want to load the sample into RAM,
1324     * thus for disk streaming.
1325     *
1326     * For 16 bit samples, the data in the buffer will be int16_t
1327     * (using native endianness). For 24 bit, the buffer will
1328     * contain three bytes per sample, little-endian.
1329     *
1330     * @param pBuffer destination buffer
1331     * @param SampleCount number of sample points to read
1332     * @returns number of successfully read sample points
1333     * @see SetPos()
1334     */
1335     unsigned long Sample::Read(void* pBuffer, unsigned long SampleCount) {
1336 iliev 2020 // TODO: startAddrsCoarseOffset, endAddrsCoarseOffset
1337 iliev 2016 if (SampleCount == 0) return 0;
1338     long pos = GetPos();
1339     if (pos + SampleCount > GetTotalFrameCount()) SampleCount = GetTotalFrameCount() - pos;
1340    
1341     if (GetFrameSize() / GetChannelCount() == 3 /* 24 bit */) {
1342     uint8_t* pBuf = (uint8_t*)pBuffer;
1343     if (SampleType == MONO_SAMPLE || SampleType == ROM_MONO_SAMPLE) {
1344 iliev 2020 pCkSmpl->Read(pBuf, SampleCount, 2);
1345     pCkSm24->Read(pBuf + SampleCount * 2, SampleCount, 1);
1346     for (int i = SampleCount - 1; i >= 0; i--) {
1347     pBuf[i*3] = pBuf[(SampleCount * 2) + i];
1348     pBuf[i*3 + 2] = pBuf[i*2 + 1];
1349     pBuf[i*3 + 1] = pBuf[i*2];
1350 iliev 2016 }
1351     } else if (SampleType == LEFT_SAMPLE || SampleType == ROM_LEFT_SAMPLE) {
1352 iliev 2020 pCkSmpl->Read(pBuf, SampleCount, 2);
1353     pCkSm24->Read(pBuf + SampleCount * 2, SampleCount, 1);
1354     for (int i = SampleCount - 1; i >= 0; i--) {
1355     pBuf[i*6] = pBuf[(SampleCount * 2) + i];
1356     pBuf[i*6 + 2] = pBuf[i*2 + 1];
1357     pBuf[i*6 + 1] = pBuf[i*2];
1358 iliev 2016 pBuf[i*6 + 3] = pBuf[i*6 + 4] = pBuf[i*6 + 5] = 0;
1359     }
1360     } else if (SampleType == RIGHT_SAMPLE || SampleType == ROM_RIGHT_SAMPLE) {
1361 iliev 2020 pCkSmpl->Read(pBuf, SampleCount, 2);
1362     pCkSm24->Read(pBuf + SampleCount * 2, SampleCount, 1);
1363     for (int i = SampleCount - 1; i >= 0; i--) {
1364     pBuf[i*6 + 3] = pBuf[(SampleCount * 2) + i];
1365     pBuf[i*6 + 5] = pBuf[i*2 + 1];
1366     pBuf[i*6 + 4] = pBuf[i*2];
1367 iliev 2016 pBuf[i*6] = pBuf[i*6 + 1] = pBuf[i*6 + 2] = 0;
1368     }
1369     }
1370     } else {
1371     if (SampleType == MONO_SAMPLE || SampleType == ROM_MONO_SAMPLE) {
1372     return pCkSmpl->Read(pBuffer, SampleCount, 2);
1373     }
1374    
1375     int16_t* pBuf = (int16_t*)pBuffer;
1376     if (SampleType == LEFT_SAMPLE || SampleType == ROM_LEFT_SAMPLE) {
1377     pCkSmpl->Read(pBuf, SampleCount, 2);
1378     for (int i = SampleCount - 1; i >= 0; i--) {
1379     pBuf[i*2] = pBuf[i];
1380     pBuf[i*2 + 1] = 0;
1381     }
1382     } else if (SampleType == RIGHT_SAMPLE || SampleType == ROM_RIGHT_SAMPLE) {
1383     pCkSmpl->Read(pBuf, SampleCount, 2);
1384     for (int i = SampleCount - 1; i >= 0; i--) {
1385     pBuf[i*2] = 0;
1386     pBuf[i*2 + 1] = pBuf[i];
1387     }
1388     }
1389     }
1390    
1391     if (pCkSmpl->GetPos() > (End * 2)) {
1392     std::cerr << "Read after the sample end. This is a BUG!" << std::endl;
1393     std::cerr << "Current position: " << GetPos() << std::endl;
1394     std::cerr << "Total number of frames: " << GetTotalFrameCount() << std::endl << std::endl;
1395     }
1396     return SampleCount;
1397     }
1398    
1399    
1400     // *************** functions ***************
1401     // *
1402    
1403     /**
1404     * Returns the name of this C++ library.
1405     */
1406     String libraryName() {
1407     return PACKAGE;
1408     }
1409    
1410     /**
1411     * Returns version of this C++ library.
1412     */
1413     String libraryVersion() {
1414     return VERSION;
1415     }
1416    
1417     } // namespace sf2

  ViewVC Help
Powered by ViewVC