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

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

Parent Directory Parent Directory | Revision Log Revision Log


Revision 2100 - (hide annotations) (download)
Sun May 30 11:39:36 2010 UTC (13 years, 10 months ago) by persson
File size: 55227 byte(s)
* sf2: changed region lookup API to avoid malloc in RT threads

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

  ViewVC Help
Powered by ViewVC