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

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

Parent Directory Parent Directory | Revision Log Revision Log


Revision 3900 - (hide annotations) (download)
Wed May 12 17:25:27 2021 UTC (2 years, 11 months ago) by schoenebeck
File size: 64899 byte(s)
* src/SF.cpp: Fix clang sanatizer warning in File::DeleteInstrument().

* Bumped version (4.3.0.svn1).

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 iliev 2206 double ToRatio(int Centibels) {
43 iliev 2026 if (Centibels == NONE) return NONE;
44 iliev 2206 if (Centibels == 0) return 1.0;
45     return pow(_200TH_ROOT_OF_10, Centibels);
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 schoenebeck 3481 Sample::Sample(File* file, RIFF::Chunk* ck, RIFF::Chunk* pCkSmpl, RIFF::Chunk* pCkSm24) {
151     this->pFile = file;
152 iliev 2016 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 2206
291     initialFilterFc = 13500;
292     initialFilterQ = 0;
293 iliev 2016 }
294    
295 iliev 2020 int Region::GetUnityNote() {
296     return overridingRootKey != -1 ? overridingRootKey : pSample->OriginalPitch;
297     }
298 iliev 2206
299     int CheckRange(std::string genName, int min, int max, int& gen) {
300     if (gen == NONE) return gen;
301 iliev 2020
302 iliev 2206 if (gen < min) {
303     std::cerr << "sf2: " << genName;
304     std::cerr << " is below the minimum allowed value (min=" << min << "): " << gen << std::endl;
305     gen = min;
306     }
307     if (gen > max) {
308     std::cerr << "sf2: " << genName;
309     std::cerr << " is above the maximum allowed value (max=" << max << "): " << gen << std::endl;
310     gen = max;
311     }
312    
313     return gen;
314     }
315    
316 iliev 2016 void Region::SetGenerator(sf2::File* pFile, GenList& Gen) {
317     switch(Gen.GenOper) {
318     case START_ADDRS_OFFSET:
319     startAddrsOffset = Gen.GenAmount.wAmount;
320     break;
321     case END_ADDRS_OFFSET:
322     if (Gen.GenAmount.shAmount <= 0) {
323     endAddrsOffset = Gen.GenAmount.shAmount;
324     } else {
325     std::cerr << "Ignoring invalid endAddrsOffset" << std::endl;
326     }
327     break;
328     case STARTLOOP_ADDRS_OFFSET:
329     startloopAddrsOffset = Gen.GenAmount.shAmount;
330 iliev 2020 LoopStart += startloopAddrsOffset;
331 iliev 2016 break;
332     case ENDLOOP_ADDRS_OFFSET:
333     endloopAddrsOffset = Gen.GenAmount.shAmount;
334 iliev 2020 LoopEnd += endloopAddrsOffset;
335 iliev 2016 break;
336     case START_ADDRS_COARSE_OFFSET:
337     startAddrsCoarseOffset = Gen.GenAmount.wAmount;
338     break;
339     case MOD_LFO_TO_PITCH:
340 iliev 2026 modLfoToPitch = Gen.GenAmount.shAmount;
341 iliev 2206 CheckRange("modLfoToPitch", -12000, 12000, modLfoToPitch);
342 iliev 2016 break;
343     case VIB_LFO_TO_PITCH:
344 iliev 2026 vibLfoToPitch = Gen.GenAmount.shAmount;
345 iliev 2206 CheckRange("vibLfoToPitch", -12000, 12000, vibLfoToPitch);
346 iliev 2016 break;
347     case MOD_ENV_TO_PITCH:
348 iliev 2026 modEnvToPitch = Gen.GenAmount.shAmount;
349 iliev 2206 CheckRange("modEnvToPitch", -12000, 12000, modEnvToPitch);
350 iliev 2016 break;
351     case INITIAL_FILTER_FC:
352 iliev 2206 initialFilterFc = Gen.GenAmount.wAmount;
353     CheckRange("initialFilterFc", 1500, 13500, initialFilterFc);
354 iliev 2016 break;
355     case INITIAL_FILTER_Q:
356 iliev 2206 initialFilterQ = Gen.GenAmount.wAmount;
357     CheckRange("initialFilterQ", 0, 960, initialFilterQ);
358 iliev 2016 break;
359     case MOD_LFO_TO_FILTER_FC:
360 iliev 2026 modLfoToFilterFc = Gen.GenAmount.shAmount;
361 iliev 2206 CheckRange("modLfoToFilterFc", -12000, 12000, modLfoToFilterFc);
362 iliev 2016 break;
363     case MOD_ENV_TO_FILTER_FC:
364 iliev 2026 modEnvToFilterFc = Gen.GenAmount.shAmount;
365 iliev 2206 CheckRange("modEnvToFilterFc", -12000, 12000, modEnvToFilterFc);
366 iliev 2016 break;
367     case END_ADDRS_COARSE_OFFSET:
368 iliev 2020 endAddrsCoarseOffset = Gen.GenAmount.wAmount;
369 iliev 2016 break;
370     case MOD_LFO_TO_VOLUME:
371 iliev 2026 modLfoToVolume = Gen.GenAmount.shAmount;
372 iliev 2206 CheckRange("modLfoToVolume", -960, 960, modLfoToVolume);
373 iliev 2016 break;
374     case CHORUS_EFFECTS_SEND:
375     break;
376     case REVERB_EFFECTS_SEND:
377     break;
378     case PAN:
379     pan = Gen.GenAmount.shAmount;
380 iliev 2206 CheckRange("pan", -500, 500, pan);
381 persson 2381 pan = pan * 64 / 500;
382 iliev 2016 if (pan > 63) pan = 63;
383     break;
384     case DELAY_MOD_LFO:
385 iliev 2026 delayModLfo = Gen.GenAmount.shAmount;
386 iliev 2206 CheckRange("delayModLfo", -12000, 5000, delayModLfo);
387 iliev 2016 break;
388     case FREQ_MOD_LFO:
389 iliev 2026 freqModLfo = Gen.GenAmount.shAmount;
390 iliev 2206 CheckRange("freqModLfo", -16000, 4500, freqModLfo);
391 iliev 2016 break;
392     case DELAY_VIB_LFO:
393 iliev 2026 delayVibLfo = Gen.GenAmount.shAmount;
394 iliev 2206 CheckRange("delayVibLfo", -12000, 5000, delayVibLfo);
395 iliev 2016 break;
396     case FREQ_VIB_LFO:
397 iliev 2026 freqVibLfo = Gen.GenAmount.shAmount;
398 iliev 2206 CheckRange("freqModLfo", -16000, 4500, freqModLfo);
399 iliev 2016 break;
400     case DELAY_MOD_ENV:
401 iliev 2026 EG2PreAttackDelay = Gen.GenAmount.shAmount;
402 iliev 2206 CheckRange("delayModEnv", -12000, 5000, EG2PreAttackDelay);
403 iliev 2016 break;
404     case ATTACK_MOD_ENV:
405 iliev 2026 EG2Attack = Gen.GenAmount.shAmount;
406 iliev 2206 CheckRange("attackModEnv", -12000, 8000, EG2Attack);
407 iliev 2016 break;
408     case HOLD_MOD_ENV:
409 iliev 2026 EG2Hold = Gen.GenAmount.shAmount;
410 iliev 2206 CheckRange("holdModEnv", -12000, 5000, EG2Hold);
411 iliev 2016 break;
412     case DECAY_MOD_ENV:
413 iliev 2026 EG2Decay = Gen.GenAmount.shAmount;
414 iliev 2206 CheckRange("decayModEnv", -12000, 8000, EG2Decay);
415 iliev 2016 break;
416     case SUSTAIN_MOD_ENV:
417 iliev 2026 EG2Sustain = Gen.GenAmount.shAmount;
418 iliev 2206 CheckRange("sustainModEnv", 0, 1000, EG2Sustain);
419 iliev 2016 break;
420 iliev 2206 case RELEASE_MOD_ENV:
421 iliev 2026 EG2Release = Gen.GenAmount.shAmount;
422 iliev 2206 CheckRange("releaseModEnv", -12000, 8000, EG2Release);
423 iliev 2016 break;
424     case KEYNUM_TO_MOD_ENV_HOLD:
425     break;
426     case KEYNUM_TO_MOD_ENV_DECAY:
427     break;
428     case DELAY_VOL_ENV:
429 iliev 2026 EG1PreAttackDelay = Gen.GenAmount.shAmount;
430 iliev 2206 CheckRange("delayVolEnv", -12000, 5000, EG1PreAttackDelay);
431 iliev 2016 break;
432     case ATTACK_VOL_ENV:
433 iliev 2026 EG1Attack = Gen.GenAmount.shAmount;
434 iliev 2206 CheckRange("attackVolEnv", -12000, 8000, EG1Attack);
435 iliev 2016 break;
436     case HOLD_VOL_ENV:
437 iliev 2026 EG1Hold = Gen.GenAmount.shAmount;
438 iliev 2206 CheckRange("holdVolEnv", -12000, 5000, EG1Hold);
439 iliev 2016 break;
440     case DECAY_VOL_ENV:
441 iliev 2026 EG1Decay = Gen.GenAmount.shAmount;
442 iliev 2206 CheckRange("decayVolEnv", -12000, 8000, EG1Decay);
443 iliev 2016 break;
444     case SUSTAIN_VOL_ENV:
445 iliev 2026 EG1Sustain = Gen.GenAmount.shAmount;
446 iliev 2206 CheckRange("sustainVolEnv", 0, 1440, EG1Sustain);
447 iliev 2016 break;
448     case RELEASE_VOL_ENV:
449 iliev 2026 EG1Release = Gen.GenAmount.shAmount;
450 iliev 2206 CheckRange("releaseVolEnv", -12000, 8000, EG1Release);
451 iliev 2016 break;
452     case KEYNUM_TO_VOL_ENV_HOLD:
453     break;
454     case KEYNUM_TO_VOL_ENV_DECAY:
455     break;
456     case INSTRUMENT: {
457     uint16_t id = Gen.GenAmount.wAmount;
458     if (id >= pFile->Instruments.size()) {
459     throw Exception("Broken SF2 file (missing instruments)");
460     }
461     pInstrument = pFile->Instruments[id];
462     break;
463     }
464     case KEY_RANGE:
465     loKey = Gen.GenAmount.ranges.byLo;
466 iliev 2206 CheckRange("loKey", 0, 127, loKey);
467 iliev 2016 hiKey = Gen.GenAmount.ranges.byHi;
468 iliev 2206 CheckRange("hiKey", 0, 127, hiKey);
469 iliev 2016 break;
470     case VEL_RANGE:
471     minVel = Gen.GenAmount.ranges.byLo;
472 iliev 2206 CheckRange("minVel", 0, 127, minVel);
473 iliev 2016 maxVel = Gen.GenAmount.ranges.byHi;
474 iliev 2206 CheckRange("maxVel", 0, 127, maxVel);
475 iliev 2016 break;
476     case STARTLOOP_ADDRS_COARSE_OFFSET:
477 iliev 2020 startloopAddrsCoarseOffset = Gen.GenAmount.wAmount;
478     LoopStart += startloopAddrsCoarseOffset * 32768;
479 iliev 2016 break;
480     case KEYNUM:
481     break;
482     case VELOCITY:
483     break;
484     case INITIAL_ATTENUATION:
485     break;
486     case ENDLOOP_ADDRS_COARSE_OFFSET:
487 iliev 2020 endloopAddrsCoarseOffset = Gen.GenAmount.wAmount;
488     LoopEnd += endloopAddrsCoarseOffset * 32768;
489 iliev 2016 break;
490     case COARSE_TUNE:
491 iliev 2020 coarseTune = Gen.GenAmount.shAmount;
492 iliev 2206 CheckRange("coarseTune", -120, 120, coarseTune);
493 iliev 2016 break;
494     case FINE_TUNE:
495     fineTune = Gen.GenAmount.shAmount;
496 iliev 2206 CheckRange("fineTune", -99, 99, fineTune);
497 iliev 2016 break;
498     case SAMPLE_ID: {
499     uint16_t sid = Gen.GenAmount.wAmount;
500     if (sid >= pFile->Samples.size()) {
501     throw Exception("Broken SF2 file (missing samples)");
502     }
503     pSample = pFile->Samples[sid];
504 iliev 2020
505     if (HasLoop) {
506     LoopStart += pSample->StartLoop;
507     LoopEnd += pSample->EndLoop;
508     if ( LoopStart < pSample->Start || LoopStart > pSample->End ||
509     LoopStart > LoopEnd || LoopEnd > pSample->End ) {
510     throw Exception("Broken SF2 file (invalid loops)");
511     }
512     LoopStart -= pSample->Start; // Relative to the sample start
513     LoopEnd -= pSample->Start; // Relative to the sample start
514     }
515 iliev 2016 break;
516     }
517     case SAMPLE_MODES:
518 iliev 2020 HasLoop = Gen.GenAmount.wAmount & 1;
519     // TODO: 3 indicates a sound which loops for the duration of key depression
520     // then proceeds to play the remainder of the sample.
521 iliev 2016 break;
522     case SCALE_TUNING:
523     break;
524     case EXCLUSIVE_CLASS:
525 iliev 2026 exclusiveClass = Gen.GenAmount.wAmount;
526 iliev 2016 break;
527     case OVERRIDING_ROOT_KEY:
528 iliev 2020 overridingRootKey = Gen.GenAmount.shAmount;
529 iliev 2206 CheckRange("overridingRootKey", -1, 127, overridingRootKey);
530 iliev 2016 break;
531     }
532     }
533    
534     void Region::SetModulator(sf2::File* pFile, ModList& Mod) {
535     modulators.push_back(ModulatorItem(Mod));
536     /*switch(srcType) {
537     case NO_CONTROLLER:
538     break;
539     case NOTE_ON_VELOCITY:
540     break;
541     case NOTE_ON_KEY_NUMBER:
542     break;
543     case POLY_PRESSURE:
544     break;
545     case CHANNEL_PRESSURE:
546     break;
547     case PITCH_WHEEL:
548     break;
549     case PITCH_WHEEL_SENSITIVITY:
550     break;
551     case LINK:
552     break;
553     default: std::cout << "Unknown controller source: " << srcType << std::endl;
554     }*/
555     }
556    
557 iliev 2026 int Region::GetPan(Region* pPresetRegion) {
558     if (pPresetRegion == NULL) return pan;
559     int p = pPresetRegion->pan + pan;
560     if (p < -64) p = -64;
561     if (p > 63) p = 63;
562     return p;
563     }
564    
565     int Region::GetFineTune(Region* pPresetRegion) {
566     if (pPresetRegion == NULL) return fineTune;
567     int t = pPresetRegion->fineTune + fineTune;
568     if (t < -99) t = -99;
569     if (t > 99) t = 99;
570     return t;
571     }
572    
573     int Region::GetCoarseTune(Region* pPresetRegion) {
574     if (pPresetRegion == NULL) return coarseTune;
575     int t = pPresetRegion->coarseTune + coarseTune;
576     if (t < -120) t = -120;
577     if (t > 120) t = 120;
578     return t;
579     }
580    
581     double Region::GetEG1PreAttackDelay(Region* pPresetRegion) {
582 iliev 2206 int val = (pPresetRegion == NULL || pPresetRegion->EG1PreAttackDelay == NONE) ?
583     EG1PreAttackDelay : pPresetRegion->EG1PreAttackDelay + EG1PreAttackDelay;
584     return ToSeconds(CheckRange("GetEG1PreAttackDelay()", -12000, 5000, val));
585 iliev 2026 }
586    
587     double Region::GetEG1Attack(Region* pPresetRegion) {
588 iliev 2206 int val = (pPresetRegion == NULL || pPresetRegion->EG1Attack == NONE) ?
589     EG1Attack : pPresetRegion->EG1Attack + EG1Attack;
590     return ToSeconds(CheckRange("GetEG1Attack()", -12000, 8000, val));
591 iliev 2026 }
592    
593     double Region::GetEG1Hold(Region* pPresetRegion) {
594 iliev 2206 int val = (pPresetRegion == NULL || pPresetRegion->EG1Hold == NONE) ?
595     EG1Hold : pPresetRegion->EG1Hold + EG1Hold;
596     return ToSeconds(CheckRange("GetEG1Hold()", -12000, 5000, val));
597 iliev 2026 }
598    
599     double Region::GetEG1Decay(Region* pPresetRegion) {
600 iliev 2206 int val = (pPresetRegion == NULL || pPresetRegion->EG1Decay == NONE) ?
601     EG1Decay : pPresetRegion->EG1Decay + EG1Decay;
602     return ToSeconds(CheckRange("GetEG1Decay()", -12000, 8000, val));
603 iliev 2026 }
604    
605 iliev 2206 int Region::GetEG1Sustain(Region* pPresetRegion) {
606     int val = (pPresetRegion == NULL || pPresetRegion->EG1Sustain == NONE) ?
607     EG1Sustain : pPresetRegion->EG1Sustain + EG1Sustain;
608     return CheckRange("GetEG1Sustain()", 0, 1440, val);
609 iliev 2026 }
610    
611     double Region::GetEG1Release(Region* pPresetRegion) {
612 iliev 2206 int val = (pPresetRegion == NULL || pPresetRegion->EG1Release == NONE) ?
613     EG1Release : pPresetRegion->EG1Release + EG1Release;
614     return ToSeconds(CheckRange("GetEG1Release()", -12000, 8000, val));
615 iliev 2026 }
616    
617     double Region::GetEG2PreAttackDelay(Region* pPresetRegion) {
618 iliev 2206 int val = (pPresetRegion == NULL || pPresetRegion->EG2PreAttackDelay == NONE) ?
619     EG2PreAttackDelay : pPresetRegion->EG2PreAttackDelay + EG2PreAttackDelay;
620     return ToSeconds(CheckRange("GetEG2PreAttackDelay()", -12000, 5000, val));
621 iliev 2026 }
622    
623     double Region::GetEG2Attack(Region* pPresetRegion) {
624 iliev 2206 int val = (pPresetRegion == NULL || pPresetRegion->EG2Attack == NONE) ?
625     EG2Attack : pPresetRegion->EG2Attack + EG2Attack;
626     return ToSeconds(CheckRange("GetEG2Attack()", -12000, 8000, val));
627 iliev 2026 }
628    
629     double Region::GetEG2Hold(Region* pPresetRegion) {
630 iliev 2206 int val = (pPresetRegion == NULL || pPresetRegion->EG2Hold == NONE) ?
631     EG2Hold : pPresetRegion->EG2Hold + EG2Hold;
632     return ToSeconds(CheckRange("GetEG2Hold()", -12000, 5000, val));
633 iliev 2026 }
634    
635     double Region::GetEG2Decay(Region* pPresetRegion) {
636 iliev 2206 int val = (pPresetRegion == NULL || pPresetRegion->EG2Decay == NONE) ?
637     EG2Decay : pPresetRegion->EG2Decay + EG2Decay;
638     return ToSeconds(CheckRange("GetEG2Decay()", -12000, 8000, val));
639 iliev 2026 }
640    
641 iliev 2206 int Region::GetEG2Sustain(Region* pPresetRegion) {
642     int val = (pPresetRegion == NULL || pPresetRegion->EG2Sustain == NONE) ?
643     EG2Sustain : pPresetRegion->EG2Sustain + EG2Sustain;
644     return CheckRange("GetEG2Sustain()", 0, 1000, val);
645 iliev 2026 }
646    
647     double Region::GetEG2Release(Region* pPresetRegion) {
648 iliev 2206 int val = (pPresetRegion == NULL || pPresetRegion->EG2Release == NONE) ?
649     EG2Release : pPresetRegion->EG2Release + EG2Release;
650     return ToSeconds(CheckRange("GetEG2Release()", -12000, 8000, val));
651 iliev 2026 }
652    
653     int Region::GetModEnvToPitch(Region* pPresetRegion) {
654 iliev 2206 int val = (pPresetRegion == NULL || pPresetRegion->modEnvToPitch == NONE) ?
655     modEnvToPitch : pPresetRegion->modEnvToPitch + modEnvToPitch;
656     return CheckRange("GetModEnvToPitch()", -12000, 12000, val);
657 iliev 2026 }
658    
659     int Region::GetModLfoToPitch(Region* pPresetRegion) {
660 iliev 2206 int val = (pPresetRegion == NULL || pPresetRegion->modLfoToPitch == NONE) ?
661     modLfoToPitch : pPresetRegion->modLfoToPitch + modLfoToPitch;
662     return CheckRange("GetModLfoToPitch()", -12000, 12000, val);
663 iliev 2026 }
664    
665     int Region::GetModEnvToFilterFc(Region* pPresetRegion) {
666 iliev 2206 int val = (pPresetRegion == NULL || pPresetRegion->modEnvToFilterFc == NONE) ?
667     modEnvToFilterFc : pPresetRegion->modEnvToFilterFc + modEnvToFilterFc;
668     return CheckRange("GetModEnvToFilterFc()", -12000, +12000, val);
669 iliev 2026 }
670    
671     int Region::GetModLfoToFilterFc(Region* pPresetRegion) {
672 iliev 2206 int val = (pPresetRegion == NULL || pPresetRegion->modLfoToFilterFc == NONE) ?
673     modLfoToFilterFc : pPresetRegion->modLfoToFilterFc + modLfoToFilterFc;
674     return CheckRange("GetModLfoToFilterFc()", -12000, +12000, val);
675 iliev 2026 }
676    
677     double Region::GetModLfoToVolume(Region* pPresetRegion) {
678 iliev 2206 int val = (pPresetRegion == NULL || pPresetRegion->modLfoToVolume == NONE) ?
679     modLfoToVolume : pPresetRegion->modLfoToVolume + modLfoToVolume;
680     return CheckRange("GetModLfoToVolume()", -960, 960, val);
681 iliev 2026 }
682    
683     double Region::GetFreqModLfo(Region* pPresetRegion) {
684 iliev 2206 int val = (pPresetRegion == NULL || pPresetRegion->freqModLfo == NONE) ?
685     freqModLfo : pPresetRegion->freqModLfo + freqModLfo;
686     return ToHz(CheckRange("GetFreqModLfo()", -16000, 4500, val));
687 iliev 2026 }
688 persson 2044
689 iliev 2026 double Region::GetDelayModLfo(Region* pPresetRegion) {
690 iliev 2206 int val = (pPresetRegion == NULL || pPresetRegion->delayModLfo == NONE) ?
691     delayModLfo : pPresetRegion->delayModLfo + delayModLfo;
692     return ToSeconds(CheckRange("GetDelayModLfo()", -12000, 5000, val));
693 iliev 2026 }
694    
695     int Region::GetVibLfoToPitch(Region* pPresetRegion) {
696 iliev 2206 int val = (pPresetRegion == NULL || pPresetRegion->vibLfoToPitch == NONE) ?
697     vibLfoToPitch : pPresetRegion->vibLfoToPitch + vibLfoToPitch;
698     return CheckRange("GetVibLfoToPitch()", -12000, 12000, val);
699 iliev 2026 }
700    
701     double Region::GetFreqVibLfo(Region* pPresetRegion) {
702 iliev 2206 int val = (pPresetRegion == NULL || pPresetRegion->freqVibLfo == NONE) ?
703     freqVibLfo : pPresetRegion->freqVibLfo + freqVibLfo;
704     return ToHz(CheckRange("GetFreqVibLfo()", -16000, 4500, val));
705 iliev 2026 }
706    
707     double Region::GetDelayVibLfo(Region* pPresetRegion) {
708 iliev 2206 int val = (pPresetRegion == NULL || pPresetRegion->delayVibLfo == NONE) ?
709     delayVibLfo : pPresetRegion->delayVibLfo + delayVibLfo;
710     return ToSeconds(CheckRange("GetDelayVibLfo()", -12000, 5000, val));
711 iliev 2026 }
712    
713 iliev 2206 int Region::GetInitialFilterFc(Region* pPresetRegion) {
714     if (pPresetRegion == NULL || pPresetRegion->initialFilterFc == NONE) return initialFilterFc;
715     int val = pPresetRegion->initialFilterFc + initialFilterFc;
716     return CheckRange("GetInitialFilterFc()", 1500, 13500, val);
717     }
718    
719     int Region::GetInitialFilterQ(Region* pPresetRegion) {
720     int val = (pPresetRegion == NULL || pPresetRegion->initialFilterQ == NONE) ?
721     initialFilterQ : pPresetRegion->initialFilterQ + initialFilterQ;
722     return CheckRange("GetInitialFilterQ()", 0, 960, val);
723     }
724    
725 iliev 2016 InstrumentBase::InstrumentBase(sf2::File* pFile) {
726     this->pFile = pFile;
727     pGlobalRegion = NULL;
728     }
729    
730     InstrumentBase::~InstrumentBase() {
731     if (pGlobalRegion) delete pGlobalRegion;
732 schoenebeck 3053 for (ssize_t i = regions.size() - 1; i >= 0; i--) {
733 iliev 2016 if (regions[i]) delete (regions[i]);
734     }
735     }
736    
737     int InstrumentBase::GetRegionCount() {
738 schoenebeck 3053 return (int) regions.size();
739 iliev 2016 }
740    
741     Region* InstrumentBase::GetRegion(int idx) {
742     if (idx < 0 || idx >= GetRegionCount()) {
743     throw Exception("Region index out of bounds");
744     }
745    
746     return regions[idx];
747     }
748    
749 persson 2100 Query::Query(InstrumentBase& instrument) : instrument(instrument) {
750     i = 0;
751     }
752    
753     Region* Query::next() {
754     while (i < instrument.GetRegionCount()) {
755     Region* r = instrument.GetRegion(i++);
756     if (((r->loKey == NONE && r->hiKey == NONE) || (key >= r->loKey && key <= r->hiKey)) &&
757     ((r->minVel == NONE && r->maxVel == NONE) || (vel >= r->minVel && vel <= r->maxVel))) {
758     return r;
759 iliev 2016 }
760     }
761 persson 2100 return 0;
762 iliev 2016 }
763    
764     Instrument::Instrument(sf2::File* pFile, RIFF::Chunk* ck) : InstrumentBase(pFile) {
765     this->pFile = pFile;
766     LoadString(ck, Name, 20);
767     InstBagNdx = ck->ReadInt16();
768     }
769    
770     Instrument::~Instrument() {
771     }
772    
773 iliev 2020 Region* Instrument::CreateRegion() {
774     Region* r = new Region;
775 iliev 2026 r->pParentInstrument = this;
776    
777 iliev 2020 if (pGlobalRegion != NULL) {
778     r->loKey = pGlobalRegion->loKey;
779     r->hiKey = pGlobalRegion->hiKey;
780     r->minVel = pGlobalRegion->minVel;
781     r->maxVel = pGlobalRegion->maxVel;
782     r->pan = pGlobalRegion->pan;
783     r->fineTune = pGlobalRegion->fineTune;
784     r->coarseTune = pGlobalRegion->coarseTune;
785     r->overridingRootKey = pGlobalRegion->overridingRootKey;
786     r->startAddrsOffset = pGlobalRegion->startAddrsOffset;
787     r->startAddrsCoarseOffset = pGlobalRegion->startAddrsCoarseOffset;
788     r->endAddrsOffset = pGlobalRegion->endAddrsOffset;
789     r->endAddrsCoarseOffset = pGlobalRegion->endAddrsCoarseOffset;
790     r->startloopAddrsOffset = pGlobalRegion->startloopAddrsOffset;
791     r->startloopAddrsCoarseOffset = pGlobalRegion->startloopAddrsCoarseOffset;
792     r->endloopAddrsOffset = pGlobalRegion->endloopAddrsOffset;
793     r->endloopAddrsCoarseOffset = pGlobalRegion->endloopAddrsCoarseOffset;
794    
795     r->EG1PreAttackDelay = pGlobalRegion->EG1PreAttackDelay;
796     r->EG1Attack = pGlobalRegion->EG1Attack;
797     r->EG1Hold = pGlobalRegion->EG1Hold;
798     r->EG1Decay = pGlobalRegion->EG1Decay;
799     r->EG1Sustain = pGlobalRegion->EG1Sustain;
800     r->EG1Release = pGlobalRegion->EG1Release;
801    
802     r->EG2PreAttackDelay = pGlobalRegion->EG2PreAttackDelay;
803     r->EG2Attack = pGlobalRegion->EG2Attack;
804     r->EG2Hold = pGlobalRegion->EG2Hold;
805     r->EG2Decay = pGlobalRegion->EG2Decay;
806     r->EG2Sustain = pGlobalRegion->EG2Sustain;
807     r->EG2Release = pGlobalRegion->EG2Release;
808    
809 iliev 2026 r->modEnvToPitch = pGlobalRegion->modEnvToPitch;
810     r->modLfoToPitch = pGlobalRegion->modLfoToPitch;
811     r->modEnvToFilterFc = pGlobalRegion->modEnvToFilterFc;
812     r->modLfoToFilterFc = pGlobalRegion->modLfoToFilterFc;
813     r->modLfoToVolume = pGlobalRegion->modLfoToVolume;
814     r->freqModLfo = pGlobalRegion->freqModLfo;
815     r->delayModLfo = pGlobalRegion->delayModLfo;
816     r->vibLfoToPitch = pGlobalRegion->vibLfoToPitch;
817     r->freqVibLfo = pGlobalRegion->freqVibLfo;
818     r->delayVibLfo = pGlobalRegion->delayVibLfo;
819 iliev 2206 r->initialFilterFc = pGlobalRegion->initialFilterFc;
820     r->initialFilterQ = pGlobalRegion->initialFilterQ;
821 iliev 2026
822 iliev 2020 r->HasLoop = pGlobalRegion->HasLoop;
823     r->LoopStart = pGlobalRegion->LoopStart;
824     r->LoopEnd = pGlobalRegion->LoopEnd;
825 iliev 2026
826     r->exclusiveClass = pGlobalRegion->exclusiveClass;
827 iliev 2020 }
828    
829     return r;
830     }
831    
832     void Instrument::DeleteRegion(Region* pRegion) {
833     for (int i = 0; i < regions.size(); i++) {
834     if (regions[i] == pRegion) {
835     delete pRegion;
836     regions[i] = NULL;
837     return;
838     }
839     }
840    
841     std::cerr << "Can't remove unknown Region" << std::endl;
842     }
843    
844 iliev 2016 void Instrument::LoadRegions(int idx1, int idx2) {
845 iliev 2020 for (int i = idx1; i < idx2; i++) {
846 iliev 2016 int gIdx1 = pFile->InstBags[i].InstGenNdx;
847     int gIdx2 = pFile->InstBags[i + 1].InstGenNdx;
848    
849     if (gIdx1 < 0 || gIdx2 < 0 || gIdx1 > gIdx2 || gIdx2 >= pFile->InstGenLists.size()) {
850     throw Exception("Broken SF2 file (invalid InstGenNdx)");
851     }
852    
853     int mIdx1 = pFile->InstBags[i].InstModNdx;
854     int mIdx2 = pFile->InstBags[i + 1].InstModNdx;
855    
856     if (mIdx1 < 0 || mIdx2 < 0 || mIdx1 > mIdx2 || mIdx2 >= pFile->InstModLists.size()) {
857     throw Exception("Broken SF2 file (invalid InstModNdx)");
858     }
859    
860 iliev 2020 Region* reg = CreateRegion();
861 persson 2044
862 iliev 2016 for (int j = gIdx1; j < gIdx2; j++) {
863     reg->SetGenerator(pFile, pFile->InstGenLists[j]);
864     // TODO: ignore generators following a sampleID generator
865     }
866    
867     for (int j = mIdx1; j < mIdx2; j++) {
868     reg->SetModulator(pFile, pFile->InstModLists[j]);
869     }
870    
871     if (reg->pSample == NULL) {
872 iliev 2020 if (i == idx1 && idx2 - idx1 > 1) {
873 iliev 2016 pGlobalRegion = reg; // global zone
874     } else {
875     std::cerr << "Ignoring instrument's region without sample" << std::endl;
876     delete reg;
877     }
878     } else {
879     regions.push_back(reg);
880     }
881     }
882     }
883    
884     Preset::Preset(sf2::File* pFile, RIFF::Chunk* ck): InstrumentBase(pFile) {
885     this->pFile = pFile;
886     LoadString(ck, Name, 20);
887     PresetNum = ck->ReadInt16();
888     Bank = ck->ReadInt16();
889     PresetBagNdx = ck->ReadInt16();
890     Library = ck->ReadInt32();
891     Genre = ck->ReadInt32();
892     Morphology = ck->ReadInt32();
893     }
894    
895     Preset::~Preset() {
896     }
897    
898 iliev 2026 Region* Preset::CreateRegion() {
899     Region* r = new Region;
900    
901     r->EG1PreAttackDelay = r->EG1Attack = r->EG1Hold = r->EG1Decay = r->EG1Sustain = r->EG1Release = NONE;
902     r->EG2PreAttackDelay = r->EG2Attack = r->EG2Hold = r->EG2Decay = r->EG2Sustain = r->EG2Release = NONE;
903     r->freqModLfo = r->delayModLfo = r->freqVibLfo = r->delayVibLfo = NONE;
904 iliev 2206 r->initialFilterFc = r->initialFilterQ = NONE;
905 iliev 2026
906     if (pGlobalRegion != NULL) {
907     r->pan = pGlobalRegion->pan;
908     r->fineTune = pGlobalRegion->fineTune;
909     r->coarseTune = pGlobalRegion->coarseTune;
910    
911     r->EG1PreAttackDelay = pGlobalRegion->EG1PreAttackDelay;
912     r->EG1Attack = pGlobalRegion->EG1Attack;
913     r->EG1Hold = pGlobalRegion->EG1Hold;
914     r->EG1Decay = pGlobalRegion->EG1Decay;
915     r->EG1Sustain = pGlobalRegion->EG1Sustain;
916     r->EG1Release = pGlobalRegion->EG1Release;
917    
918     r->EG2PreAttackDelay = pGlobalRegion->EG2PreAttackDelay;
919     r->EG2Attack = pGlobalRegion->EG2Attack;
920     r->EG2Hold = pGlobalRegion->EG2Hold;
921     r->EG2Decay = pGlobalRegion->EG2Decay;
922     r->EG2Sustain = pGlobalRegion->EG2Sustain;
923     r->EG2Release = pGlobalRegion->EG2Release;
924    
925     r->modEnvToPitch = pGlobalRegion->modEnvToPitch;
926     r->modLfoToPitch = pGlobalRegion->modLfoToPitch;
927     r->modEnvToFilterFc = pGlobalRegion->modEnvToFilterFc;
928     r->modLfoToFilterFc = pGlobalRegion->modLfoToFilterFc;
929     r->modLfoToVolume = pGlobalRegion->modLfoToVolume;
930     r->freqModLfo = pGlobalRegion->freqModLfo;
931     r->delayModLfo = pGlobalRegion->delayModLfo;
932     r->vibLfoToPitch = pGlobalRegion->vibLfoToPitch;
933     r->freqVibLfo = pGlobalRegion->freqVibLfo;
934     r->delayVibLfo = pGlobalRegion->delayVibLfo;
935 iliev 2206 r->initialFilterFc = pGlobalRegion->initialFilterFc;
936     r->initialFilterQ = pGlobalRegion->initialFilterQ;
937 iliev 2026 }
938    
939     return r;
940     }
941    
942 iliev 2016 void Preset::LoadRegions(int idx1, int idx2) {
943 iliev 2020 for (int i = idx1; i < idx2; i++) {
944 iliev 2016 int gIdx1 = pFile->PresetBags[i].GenNdx;
945     int gIdx2 = pFile->PresetBags[i + 1].GenNdx;
946    
947     if (gIdx1 < 0 || gIdx2 < 0 || gIdx1 > gIdx2 || gIdx2 >= pFile->PresetGenLists.size()) {
948     throw Exception("Broken SF2 file (invalid PresetGenNdx)");
949     }
950    
951 iliev 2026 Region* reg = CreateRegion();
952 iliev 2016
953     for (int j = gIdx1; j < gIdx2; j++) {
954     reg->SetGenerator(pFile, pFile->PresetGenLists[j]);
955     }
956     if (reg->pInstrument == NULL) {
957 iliev 2020 if (i == idx1 && idx2 - idx1 > 1) {
958 iliev 2016 pGlobalRegion = reg; // global zone
959     } else {
960     std::cerr << "Ignoring preset's region without instrument" << std::endl;
961     delete reg;
962     }
963     } else {
964     regions.push_back(reg);
965     }
966     }
967     }
968    
969     /** @brief Constructor.
970     *
971     * Load an existing SF2 file.
972     *
973     * @param pRIFF - pointer to a RIFF file which is actually the SF2 file
974     * to load
975     * @throws Exception if given file is not a SF2 file, expected chunks
976     * are missing
977     */
978     File::File(RIFF::File* pRIFF) {
979     if (!pRIFF) throw Exception("NULL pointer reference to RIFF::File object.");
980     this->pRIFF = pRIFF;
981    
982     if (pRIFF->GetListType() != RIFF_TYPE_SF2) {
983     throw Exception("Not a SF2 file");
984     }
985    
986     pInfo = new Info(pRIFF);
987     if (pInfo->pVer->Major != 2) {
988     throw Exception("Unsupported version: " + ToString(pInfo->pVer->Major));
989     }
990    
991     RIFF::List* lstSDTA = pRIFF->GetSubList(LIST_TYPE_SDTA);
992     if (lstSDTA == NULL) {
993     throw Exception("Broken SF2 file (missing sdta)");
994     }
995    
996     RIFF::Chunk* pCkSmpl = lstSDTA->GetSubChunk(CHUNK_ID_SMPL);
997     RIFF::Chunk* pCkSm24 = lstSDTA->GetSubChunk(CHUNK_ID_SM24);
998     if (pCkSmpl != NULL && pCkSm24 != NULL) {
999     long l = pCkSmpl->GetSize() / 2;
1000     if (l%2) l++;
1001     if (pCkSm24->GetSize() != l) {
1002     pCkSm24 = NULL; // ignoring sm24 due to invalid size
1003     }
1004     }
1005    
1006     RIFF::List* lstPDTA = pRIFF->GetSubList(LIST_TYPE_PDTA);
1007     if (lstPDTA == NULL) {
1008     throw Exception("Broken SF2 file (missing pdta)");
1009     }
1010    
1011     RIFF::Chunk* ck = lstPDTA->GetSubChunk(CHUNK_ID_PHDR);
1012     if (ck->GetSize() < 38) {
1013     throw Exception("Broken SF2 file (broken phdr)");
1014     }
1015    
1016 schoenebeck 3053 int count = (int) ck->GetSize() / 38;
1017 iliev 2016 for (int i = 0; i < count; i++) {
1018     Presets.push_back(new Preset(this, ck));
1019     }
1020    
1021     ck = GetMandatoryChunk(lstPDTA, CHUNK_ID_PBAG);
1022     if (ck->GetSize() < 4 || (ck->GetSize() % 4)) {
1023     throw Exception("Broken SF2 file (broken pbag)");
1024     }
1025    
1026 schoenebeck 3053 count = int(ck->GetSize() / 4);
1027 iliev 2016 for (int i = 0; i < count; i++) {
1028     PresetBag pb;
1029     pb.GenNdx = ck->ReadInt16();
1030     pb.ModNdx = ck->ReadInt16();
1031     PresetBags.push_back(pb);
1032     }
1033     //std::cout << "Preset bags: " << PresetBags.size() << std::endl;
1034    
1035     ck = GetMandatoryChunk(lstPDTA, CHUNK_ID_PMOD);
1036     if (ck->GetSize() % 10) {
1037     throw Exception("Broken SF2 file (broken pmod)");
1038     }
1039    
1040 schoenebeck 3053 count = int(ck->GetSize() / 10);
1041 iliev 2016 for (int i = 0; i < count; i++) {
1042     ModList ml;
1043     ml.ModSrcOper = ck->ReadInt16();
1044     ml.ModDestOper = ck->ReadInt16();
1045     ml.ModAmount = ck->ReadInt16();
1046     ml.ModAmtSrcOper = ck->ReadInt16();
1047     ml.ModTransOper = ck->ReadInt16();
1048     PresetModLists.push_back(ml);
1049     }
1050     //std::cout << "Preset mod lists: " << PresetModLists.size() << std::endl;
1051    
1052     ck = GetMandatoryChunk(lstPDTA, CHUNK_ID_PGEN);
1053     if (ck->GetSize() < 4 || (ck->GetSize() % 4)) {
1054     throw Exception("Broken SF2 file (broken pgen)");
1055     }
1056    
1057 schoenebeck 3053 count = int(ck->GetSize() / 4);
1058 iliev 2016 for (int i = 0; i < count; i++) {
1059     GenList gl;
1060     gl.GenOper = ck->ReadInt16();
1061     gl.GenAmount.wAmount = ck->ReadInt16();
1062     PresetGenLists.push_back(gl);
1063     }
1064     //std::cout << "Preset gen lists: " << PresetGenLists.size() << std::endl;
1065    
1066     ck = GetMandatoryChunk(lstPDTA, CHUNK_ID_INST);
1067     if (ck->GetSize() < (22 * 2) || (ck->GetSize() % 22)) {
1068     throw Exception("Broken SF2 file (broken inst)");
1069     }
1070 schoenebeck 3053 count = int(ck->GetSize() / 22);
1071 iliev 2016 for (int i = 0; i < count; i++) {
1072     Instruments.push_back(new Instrument(this, ck));
1073     }
1074    
1075     ck = GetMandatoryChunk(lstPDTA, CHUNK_ID_IBAG);
1076     if (ck->GetSize() < 4 || (ck->GetSize() % 4)) {
1077     throw Exception("Broken SF2 file (broken ibag)");
1078     }
1079    
1080 schoenebeck 3053 count = int(ck->GetSize() / 4);
1081 iliev 2016 for (int i = 0; i < count; i++) {
1082     InstBag ib;
1083     ib.InstGenNdx = ck->ReadInt16();
1084     ib.InstModNdx = ck->ReadInt16();
1085     InstBags.push_back(ib);
1086     }
1087     //std::cout << "Instrument bags: " << InstBags.size() << std::endl;
1088    
1089     ck = GetMandatoryChunk(lstPDTA, CHUNK_ID_IMOD);
1090     if (ck->GetSize() % 10) {
1091     throw Exception("Broken SF2 file (broken imod)");
1092     }
1093    
1094 schoenebeck 3053 count = int(ck->GetSize() / 10);
1095 iliev 2016 for (int i = 0; i < count; i++) {
1096     ModList ml;
1097     ml.ModSrcOper = ck->ReadInt16();
1098     ml.ModDestOper = ck->ReadInt16();
1099     ml.ModAmount = ck->ReadInt16();
1100     ml.ModAmtSrcOper = ck->ReadInt16();
1101     ml.ModTransOper = ck->ReadInt16();
1102     InstModLists.push_back(ml);
1103     }
1104     //std::cout << "Instrument mod lists: " << InstModLists.size() << std::endl;
1105    
1106     ck = GetMandatoryChunk(lstPDTA, CHUNK_ID_IGEN);
1107     if (ck->GetSize() < 4 || (ck->GetSize() % 4)) {
1108     throw Exception("Broken SF2 file (broken igen)");
1109     }
1110    
1111 schoenebeck 3053 count = int(ck->GetSize() / 4);
1112 iliev 2016 for (int i = 0; i < count; i++) {
1113     GenList gl;
1114     gl.GenOper = ck->ReadInt16();
1115     gl.GenAmount.wAmount = ck->ReadInt16();
1116     InstGenLists.push_back(gl);
1117     }
1118     //std::cout << "Instrument gen lists: " << InstGenLists.size() << std::endl;
1119    
1120     ck = GetMandatoryChunk(lstPDTA, CHUNK_ID_SHDR);
1121     if ((ck->GetSize() % 46)) {
1122     throw Exception("Broken SF2 file (broken shdr)");
1123     }
1124 schoenebeck 3053 count = int(ck->GetSize() / 46);
1125 iliev 2016 for (int i = 0; i < count; i++) {
1126 schoenebeck 3481 Samples.push_back(new Sample(this, ck, pCkSmpl, pCkSm24));
1127 iliev 2016 }
1128    
1129     // Loading instrument regions
1130     for (int i = 0; i < Instruments.size() - 1; i++) {
1131     Instrument* instr = Instruments[i];
1132     int x1 = instr->InstBagNdx;
1133     int x2 = Instruments[i + 1]->InstBagNdx;
1134     if (x1 < 0 || x2 < 0 || x1 > x2 || x2 >= InstBags.size()) {
1135     throw Exception("Broken SF2 file (invalid InstBagNdx)");
1136     }
1137    
1138     instr->LoadRegions(x1, x2);
1139     }
1140    
1141     // Loading preset regions
1142     for (int i = 0; i < Presets.size() - 1; i++) {
1143     Preset* preset = Presets[i];
1144     int x1 = preset->PresetBagNdx;
1145     int x2 = Presets[i + 1]->PresetBagNdx;
1146     if (x1 < 0 || x2 < 0 || x1 > x2 || x2 >= PresetBags.size()) {
1147     throw Exception("Broken SF2 file (invalid PresetBagNdx)");
1148     }
1149    
1150     preset->LoadRegions(x1, x2);
1151     }
1152     }
1153    
1154     File::~File() {
1155     delete pInfo;
1156 schoenebeck 3053 for (ssize_t i = Presets.size() - 1; i >= 0; i--) {
1157 iliev 2016 if (Presets[i]) delete (Presets[i]);
1158     }
1159 schoenebeck 3053 for (ssize_t i = Instruments.size() - 1; i >= 0; i--) {
1160 iliev 2016 if (Instruments[i]) delete (Instruments[i]);
1161     }
1162 schoenebeck 3053 for (ssize_t i = Samples.size() - 1; i >= 0; i--) {
1163 iliev 2016 if (Samples[i]) delete (Samples[i]);
1164     }
1165     }
1166 persson 2044
1167 iliev 2016 int File::GetPresetCount() {
1168 schoenebeck 3053 return (int) Presets.size() - 1; // exclude terminal preset (EOP)
1169 iliev 2016 }
1170    
1171     Preset* File::GetPreset(int idx) {
1172     if (idx < 0 || idx >= GetPresetCount()) {
1173     throw Exception("Preset index out of bounds");
1174     }
1175    
1176     return Presets[idx];
1177     }
1178    
1179     int File::GetInstrumentCount() {
1180 schoenebeck 3053 return (int) Instruments.size() - 1; // exclude terminal instrument (EOI)
1181 iliev 2016 }
1182    
1183     Instrument* File::GetInstrument(int idx) {
1184     if (idx < 0 || idx >= GetInstrumentCount()) {
1185     throw Exception("Instrument index out of bounds");
1186     }
1187    
1188     return Instruments[idx];
1189     }
1190    
1191 iliev 2020 void File::DeleteInstrument(Instrument* pInstrument) {
1192 schoenebeck 3900 if (!pInstrument) return;
1193    
1194 iliev 2020 for (int i = 0; i < GetPresetCount(); i++) {
1195     Preset* p = GetPreset(i);
1196     if (p == NULL) continue;
1197     for (int j = p->GetRegionCount() - 1; j >= 0 ; j--) {
1198     if (p->GetRegion(j) && p->GetRegion(j)->pInstrument == pInstrument) {
1199     p->GetRegion(j)->pInstrument = NULL;
1200     }
1201     }
1202     }
1203    
1204     for (int i = 0; i < GetInstrumentCount(); i++) {
1205     if (GetInstrument(i) == pInstrument) {
1206     Instruments[i] = NULL;
1207     delete pInstrument;
1208 schoenebeck 3900 // an instrument instance only exists once in the list, so stop
1209     // here (which also silences a clang sanatizer warning about
1210     // potential multiple memory releases of pInstrument above)
1211     return;
1212 iliev 2020 }
1213     }
1214     }
1215    
1216 iliev 2016 int File::GetSampleCount() {
1217 schoenebeck 3053 return (int) Samples.size() - 1; // exclude terminal sample (EOS)
1218 iliev 2016 }
1219    
1220     Sample* File::GetSample(int idx) {
1221     if (idx < 0 || idx >= GetSampleCount()) {
1222     throw Exception("Sample index out of bounds");
1223     }
1224    
1225     return Samples[idx];
1226     }
1227    
1228     void File::DeleteSample(Sample* pSample) {
1229 iliev 2020 // Sanity check
1230     for (int i = GetInstrumentCount() - 1; i >= 0; i--) {
1231     Instrument* pInstr = GetInstrument(i);
1232     if (pInstr == NULL) continue;
1233    
1234     for (int j = pInstr->GetRegionCount() - 1; j >= 0 ; j--) {
1235     if (pInstr->GetRegion(j) && pInstr->GetRegion(j)->GetSample() == pSample) {
1236     std::cerr << "Deleting sample which is still in use" << std::endl;
1237     }
1238     }
1239     }
1240     ///////
1241    
1242 iliev 2016 for (int i = 0; i < GetSampleCount(); i++) {
1243     if (Samples[i] == pSample) {
1244     delete pSample;
1245     Samples[i] = NULL;
1246     return;
1247     }
1248     }
1249    
1250     throw Exception("Unknown sample: " + pSample->Name);
1251     }
1252    
1253     bool File::HasSamples() {
1254     for (int i = 0; i < GetSampleCount(); i++) {
1255     if (Samples[i] != NULL) return true;
1256     }
1257    
1258     return false;
1259     }
1260    
1261 schoenebeck 3481 RIFF::File* File::GetRiffFile() {
1262     return pRIFF;
1263     }
1264    
1265 iliev 2016 /**
1266     * Loads the whole sample wave into RAM. Use
1267     * ReleaseSampleData() to free the memory if you don't need the cached
1268     * sample data anymore.
1269     *
1270     * @returns buffer_t structure with start address and size of the buffer
1271     * in bytes
1272     * @see ReleaseSampleData(), Read(), SetPos()
1273     */
1274     Sample::buffer_t Sample::LoadSampleData() {
1275     return LoadSampleDataWithNullSamplesExtension(GetTotalFrameCount(), 0); // 0 amount of NullSamples
1276     }
1277    
1278     /**
1279     * Reads and caches the first \a SampleCount
1280     * numbers of SamplePoints in RAM. Use ReleaseSampleData() to free the
1281     * memory space if you don't need the cached samples anymore.
1282     * Read the <i>Size</i> member of the <i>buffer_t</i> structure
1283     * that will be returned to determine the actual cached samples, but note
1284     * that the size is given in bytes! You get the number of actually cached
1285     * samples by dividing it by the frame size of the sample:
1286     * @code
1287 persson 2044 * buffer_t buf = pSample->LoadSampleData(acquired_samples);
1288     * long cachedsamples = buf.Size / pSample->FrameSize;
1289 iliev 2016 * @endcode
1290     *
1291     * @param SampleCount - number of sample points to load into RAM
1292     * @returns buffer_t structure with start address and size of
1293     * the cached sample data in bytes
1294     * @see ReleaseSampleData(), Read(), SetPos()
1295     */
1296     Sample::buffer_t Sample::LoadSampleData(unsigned long SampleCount) {
1297     return LoadSampleDataWithNullSamplesExtension(SampleCount, 0); // 0 amount of NullSamples
1298     }
1299    
1300     /**
1301     * Loads the whole sample wave into RAM. Use
1302     * ReleaseSampleData() to free the memory if you don't need the cached
1303     * sample data anymore.
1304     * The method will add \a NullSamplesCount silence samples past the
1305     * official buffer end (this won't affect the 'Size' member of the
1306     * buffer_t structure, that means 'Size' always reflects the size of the
1307     * actual sample data, the buffer might be bigger though). Silence
1308     * samples past the official buffer are needed for differential
1309     * algorithms that always have to take subsequent samples into account
1310     * (resampling/interpolation would be an important example) and avoids
1311     * memory access faults in such cases.
1312     *
1313     * @param NullSamplesCount - number of silence samples the buffer should
1314     * be extended past it's data end
1315     * @returns buffer_t structure with start address and
1316     * size of the buffer in bytes
1317     * @see ReleaseSampleData(), Read(), SetPos()
1318     */
1319     Sample::buffer_t Sample::LoadSampleDataWithNullSamplesExtension(uint NullSamplesCount) {
1320     return LoadSampleDataWithNullSamplesExtension(GetTotalFrameCount(), NullSamplesCount);
1321     }
1322    
1323     /**
1324     * Reads and caches the first \a SampleCount
1325     * numbers of SamplePoints in RAM. Use ReleaseSampleData() to free the
1326     * memory space if you don't need the cached samples anymore.
1327     * Read the <i>Size</i> member of the <i>buffer_t</i> structure
1328     * that will be returned to determine the actual cached samples, but note
1329     * that the size is given in bytes! You get the number of actually cached
1330     * samples by dividing it by the frame size of the sample:
1331     * @code
1332 persson 2044 * buffer_t buf = pSample->LoadSampleDataWithNullSamplesExtension(acquired_samples, null_samples);
1333     * long cachedsamples = buf.Size / pSample->FrameSize;
1334 iliev 2016 * @endcode
1335     * The method will add \a NullSamplesCount silence samples past the
1336     * official buffer end (this won't affect the 'Size' member of the
1337     * buffer_t structure, that means 'Size' always reflects the size of the
1338     * actual sample data, the buffer might be bigger though). Silence
1339     * samples past the official buffer are needed for differential
1340     * algorithms that always have to take subsequent samples into account
1341     * (resampling/interpolation would be an important example) and avoids
1342     * memory access faults in such cases.
1343     *
1344     * @param SampleCount - number of sample points to load into RAM
1345     * @param NullSamplesCount - number of silence samples the buffer should
1346     * be extended past it's data end
1347     * @returns buffer_t structure with start address and
1348     * size of the cached sample data in bytes
1349     * @see ReleaseSampleData(), Read(), SetPos()
1350     */
1351     Sample::buffer_t Sample::LoadSampleDataWithNullSamplesExtension(unsigned long SampleCount, uint NullSamplesCount) {
1352     if (SampleCount > GetTotalFrameCount()) SampleCount = GetTotalFrameCount();
1353     if (RAMCache.pStart) delete[] (int8_t*) RAMCache.pStart;
1354     unsigned long allocationsize = (SampleCount + NullSamplesCount) * GetFrameSize();
1355     SetPos(0); // reset read position to begin of sample
1356     RAMCache.pStart = new int8_t[allocationsize];
1357     RAMCache.Size = Read(RAMCache.pStart, SampleCount) * GetFrameSize();
1358     RAMCache.NullExtensionSize = allocationsize - RAMCache.Size;
1359     // fill the remaining buffer space with silence samples
1360     memset((int8_t*)RAMCache.pStart + RAMCache.Size, 0, RAMCache.NullExtensionSize);
1361     return GetCache();
1362     }
1363    
1364     /**
1365     * Returns current cached sample points. A buffer_t structure will be
1366     * returned which contains address pointer to the begin of the cache and
1367     * the size of the cached sample data in bytes. Use
1368     * <i>LoadSampleData()</i> to cache a specific amount of sample points in
1369     * RAM.
1370     *
1371     * @returns buffer_t structure with current cached sample points
1372     * @see LoadSampleData();
1373     */
1374     Sample::buffer_t Sample::GetCache() {
1375     // return a copy of the buffer_t structure
1376     buffer_t result;
1377     result.Size = this->RAMCache.Size;
1378     result.pStart = this->RAMCache.pStart;
1379     result.NullExtensionSize = this->RAMCache.NullExtensionSize;
1380     return result;
1381     }
1382    
1383     /**
1384     * Frees the cached sample from RAM if loaded with
1385     * <i>LoadSampleData()</i> previously.
1386     *
1387     * @see LoadSampleData();
1388     */
1389     void Sample::ReleaseSampleData() {
1390     if (RAMCache.pStart) delete[] (int8_t*) RAMCache.pStart;
1391     RAMCache.pStart = NULL;
1392     RAMCache.Size = 0;
1393     RAMCache.NullExtensionSize = 0;
1394     }
1395    
1396     /**
1397     * Sets the position within the sample (in sample points, not in
1398     * bytes). Use this method and <i>Read()</i> if you don't want to load
1399     * the sample into RAM, thus for disk streaming.
1400     *
1401     * @param SampleCount number of sample points to jump
1402     * @returns the new sample position
1403     * @see Read()
1404     */
1405     unsigned long Sample::SetPos(unsigned long SampleCount) {
1406     pCkSmpl->SetPos((Start * 2) + (SampleCount * 2), RIFF::stream_start);
1407     if(pCkSm24) pCkSm24->SetPos(Start + SampleCount, RIFF::stream_start);
1408     return SampleCount;
1409     }
1410    
1411     /**
1412     * Returns the current position in the sample (in sample points).
1413     */
1414     unsigned long Sample::GetPos() {
1415     return (pCkSmpl->GetPos() - (Start * 2)) / 2;
1416     }
1417    
1418 schoenebeck 2780 // Actual implementation of Sample::Read*() code. Wrapped into a template for a) runtime effeciency and b) code redundancy reasons.
1419     template<bool CLEAR>
1420     inline unsigned long ReadSample(Sample* pSample, void* pBuffer, unsigned long SampleCount, Sample::buffer_t* tempBuffer = NULL) {
1421 iliev 2020 // TODO: startAddrsCoarseOffset, endAddrsCoarseOffset
1422 iliev 2016 if (SampleCount == 0) return 0;
1423 schoenebeck 2780 long pos = pSample->GetPos();
1424     if (pos + SampleCount > pSample->GetTotalFrameCount())
1425     SampleCount = pSample->GetTotalFrameCount() - pos;
1426     if (!CLEAR) {
1427     if (tempBuffer->Size < SampleCount * pSample->GetFrameSize()) {
1428     std::cerr << "sf2::Sample error: tempBuffer too small. This is a BUG!" << std::endl;
1429     return 0;
1430     }
1431     }
1432 persson 2044
1433 schoenebeck 2780 if (pSample->GetFrameSize() / pSample->GetChannelCount() == 3 /* 24 bit */) {
1434     uint8_t* const pTmpBuf = (uint8_t*) ((CLEAR) ? pBuffer : tempBuffer->pStart);
1435     uint8_t* const pBuf = (uint8_t*)pBuffer;
1436     if (pSample->SampleType == Sample::MONO_SAMPLE || pSample->SampleType == Sample::ROM_MONO_SAMPLE) {
1437     pSample->pCkSmpl->Read(pTmpBuf, SampleCount, 2);
1438     pSample->pCkSm24->Read(pTmpBuf + SampleCount * 2, SampleCount, 1);
1439 schoenebeck 3053 for (long i = SampleCount - 1; i >= 0; i--) {
1440 schoenebeck 2780 pBuf[i*3] = pTmpBuf[(SampleCount * 2) + i];
1441     pBuf[i*3 + 2] = pTmpBuf[i*2 + 1];
1442     pBuf[i*3 + 1] = pTmpBuf[i*2];
1443 iliev 2016 }
1444 schoenebeck 2780 } else if (pSample->SampleType == Sample::LEFT_SAMPLE || pSample->SampleType == Sample::ROM_LEFT_SAMPLE) {
1445     pSample->pCkSmpl->Read(pTmpBuf, SampleCount, 2);
1446     pSample->pCkSm24->Read(pTmpBuf + SampleCount * 2, SampleCount, 1);
1447 schoenebeck 3053 for (long i = SampleCount - 1; i >= 0; i--) {
1448 schoenebeck 2780 pBuf[i*6] = pTmpBuf[(SampleCount * 2) + i];
1449     pBuf[i*6 + 2] = pTmpBuf[i*2 + 1];
1450     pBuf[i*6 + 1] = pTmpBuf[i*2];
1451     if (CLEAR)
1452     pBuf[i*6 + 3] = pBuf[i*6 + 4] = pBuf[i*6 + 5] = 0;
1453 iliev 2016 }
1454 schoenebeck 2780 } else if (pSample->SampleType == Sample::RIGHT_SAMPLE || pSample->SampleType == Sample::ROM_RIGHT_SAMPLE) {
1455     pSample->pCkSmpl->Read(pTmpBuf, SampleCount, 2);
1456     pSample->pCkSm24->Read(pTmpBuf + SampleCount * 2, SampleCount, 1);
1457 schoenebeck 3053 for (long i = SampleCount - 1; i >= 0; i--) {
1458 schoenebeck 2780 pBuf[i*6 + 3] = pTmpBuf[(SampleCount * 2) + i];
1459     pBuf[i*6 + 5] = pTmpBuf[i*2 + 1];
1460     pBuf[i*6 + 4] = pTmpBuf[i*2];
1461     if (CLEAR)
1462     pBuf[i*6] = pBuf[i*6 + 1] = pBuf[i*6 + 2] = 0;
1463 iliev 2016 }
1464     }
1465     } else {
1466 schoenebeck 2780 if (pSample->SampleType == Sample::MONO_SAMPLE || pSample->SampleType == Sample::ROM_MONO_SAMPLE) {
1467     return pSample->pCkSmpl->Read(pBuffer, SampleCount, 2);
1468 iliev 2016 }
1469    
1470 schoenebeck 2780 int16_t* const pTmpBuf = (int16_t*) ((CLEAR) ? pBuffer : tempBuffer->pStart);
1471     int16_t* const pBuf = (int16_t*) pBuffer;
1472     if (pSample->SampleType == Sample::LEFT_SAMPLE || pSample->SampleType == Sample::ROM_LEFT_SAMPLE) {
1473     pSample->pCkSmpl->Read(pTmpBuf, SampleCount, 2);
1474 schoenebeck 3053 for (long i = SampleCount - 1; i >= 0; i--) {
1475 schoenebeck 2780 pBuf[i*2] = pTmpBuf[i];
1476     if (CLEAR)
1477     pBuf[i*2 + 1] = 0;
1478 iliev 2016 }
1479 schoenebeck 2780 } else if (pSample->SampleType == Sample::RIGHT_SAMPLE || pSample->SampleType == Sample::ROM_RIGHT_SAMPLE) {
1480     pSample->pCkSmpl->Read(pTmpBuf, SampleCount, 2);
1481 schoenebeck 3053 for (long i = SampleCount - 1; i >= 0; i--) {
1482 schoenebeck 2780 if (CLEAR)
1483     pBuf[i*2] = 0;
1484     pBuf[i*2 + 1] = pTmpBuf[i];
1485 iliev 2016 }
1486     }
1487     }
1488    
1489 schoenebeck 2780 if (pSample->pCkSmpl->GetPos() > (pSample->End * 2)) {
1490 iliev 2016 std::cerr << "Read after the sample end. This is a BUG!" << std::endl;
1491 schoenebeck 2780 std::cerr << "Current position: " << pSample->GetPos() << std::endl;
1492     std::cerr << "Total number of frames: " << pSample->GetTotalFrameCount() << std::endl << std::endl;
1493 iliev 2016 }
1494     return SampleCount;
1495     }
1496    
1497 schoenebeck 2780 /**
1498     * Reads \a SampleCount number of sample points from the current
1499     * position into the buffer pointed by \a pBuffer and increments the
1500     * position within the sample. Use this method
1501     * and <i>SetPos()</i> if you don't want to load the sample into RAM,
1502     * thus for disk streaming.
1503     *
1504     * For 16 bit samples, the data in the buffer will be int16_t
1505     * (using native endianness). For 24 bit, the buffer will
1506     * contain three bytes per sample, little-endian.
1507     *
1508     * Stereo Samples: stereo samples are stored as a pair of mono samples with
1509     * SoundFont 2. Due to historical reasons, this Read() method expects
1510     * @a pBuffer to be a stereo buffer, however only the audio channel covered
1511     * by the sample data of this sample will be filled. The other audio channel
1512     * of @a pBuffer will be set to zero. This is probably not what you want.
1513     * So you might want to use ReadNoClear() instead.
1514     *
1515     * @param pBuffer destination buffer
1516     * @param SampleCount number of sample points to read
1517     * @returns number of successfully read sample points
1518     * @see SetPos(), ReadNoClear()
1519     */
1520     unsigned long Sample::Read(void* pBuffer, unsigned long SampleCount) {
1521     return ReadSample<true>(this, pBuffer, SampleCount);
1522     }
1523 iliev 2016
1524 schoenebeck 2780 /**
1525     * Reads \a SampleCount number of sample points from the current
1526     * position into the buffer pointed by \a pBuffer and increments the
1527     * position within the sample. Use this method
1528     * and <i>SetPos()</i> if you don't want to load the sample into RAM,
1529     * thus for disk streaming.
1530     *
1531     * For 16 bit samples, the data in the buffer will be int16_t
1532     * (using native endianness). For 24 bit, the buffer will
1533     * contain three bytes per sample, little-endian.
1534     *
1535     * Stereo Samples: stereo samples are stored as a pair of mono samples with
1536     * SoundFont 2. This ReadNoClear() method expects @a pBuffer to be a stereo
1537     * buffer, however only the audio channel covered by the sample data of this
1538     * sample will be filled. The other audio channel
1539     * of @a pBuffer will remain untouched. So you might pass the same
1540     * @a pBuffer to the other, linked sample to actually get the interleaved
1541     * stereo audio stream. To avoid destroying the other audio channel's data
1542     * you must pass an external, tempoary working buffer @a tempBuffer, which
1543     * should already be allocated to the size required to decode the requested
1544     * length of sample data. That @a tempBuffer is only used by ReadNoClear()
1545     * to fulfill its work, it does not contain any useful data after this
1546     * method returned.
1547     *
1548     * @param pBuffer destination buffer
1549     * @param SampleCount number of sample points to read
1550     * @param tempBuffer temporary work buffer (must be pre-allocated large enough)
1551     * @returns number of successfully read sample points
1552     * @see SetPos(), Read()
1553     */
1554     unsigned long Sample::ReadNoClear(void* pBuffer, unsigned long SampleCount, buffer_t& tempBuffer) {
1555     return ReadSample<false>(this, pBuffer, SampleCount, &tempBuffer);
1556     }
1557    
1558    
1559 iliev 2016 // *************** functions ***************
1560     // *
1561    
1562     /**
1563     * Returns the name of this C++ library.
1564     */
1565     String libraryName() {
1566     return PACKAGE;
1567     }
1568    
1569     /**
1570     * Returns version of this C++ library.
1571     */
1572     String libraryVersion() {
1573     return VERSION;
1574     }
1575    
1576     } // namespace sf2

  ViewVC Help
Powered by ViewVC