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

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

Parent Directory Parent Directory | Revision Log Revision Log


Revision 2780 - (hide annotations) (download)
Thu Jul 2 20:04:16 2015 UTC (8 years, 9 months ago) by schoenebeck
File size: 64403 byte(s)
* src/SF.cpp, src/SF.h:
- Added new method Sample::ReadNoClear().
* Added new command line tool "sf2extract" (and a man page for it).
* Bumped version (3.3.0.svn29).

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

  ViewVC Help
Powered by ViewVC