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

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

Parent Directory Parent Directory | Revision Log Revision Log


Revision 2202 - (hide annotations) (download)
Sat Jul 9 16:43:35 2011 UTC (12 years, 8 months ago) by persson
File size: 55290 byte(s)
* sf2: fixed GetEG1Sustain which didn't return correct value

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

  ViewVC Help
Powered by ViewVC