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

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

Parent Directory Parent Directory | Revision Log Revision Log


Revision 2020 - (hide annotations) (download)
Fri Oct 30 16:25:27 2009 UTC (12 years, 8 months ago) by iliev
File size: 46016 byte(s)
* sf2: 24bit support
* sf2: loop support
* sf2: implemented overridingRootKey
* sf2: implemented instrument global region
* sf2: bugfix: some regions were ignored

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

  ViewVC Help
Powered by ViewVC