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

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

Parent Directory Parent Directory | Revision Log Revision Log


Revision 2014 - (hide annotations) (download)
Sun Oct 25 22:11:41 2009 UTC (14 years, 6 months ago) by iliev
File size: 39361 byte(s)
* implemented EG2

1 iliev 2008 /***************************************************************************
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 iliev 2014 #define _1200TH_ROOT_OF_2 1.000577789506555
35     #define _200TH_ROOT_OF_10 1.011579454259899
36 iliev 2008
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 iliev 2014 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 iliev 2008 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 iliev 2014 bool Sample::HasLoops() {
200     return StartLoop != 0 && EndLoop != 0;
201     }
202    
203 iliev 2008 /**
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     PlaybackState* pPlaybackState
233     ) {
234 iliev 2014 SetPos(pPlaybackState->position);
235     long frames = Read(pBuffer, FrameCount);
236     pPlaybackState->position = GetPos();
237     // TODO: Implement looping
238     return frames;
239 iliev 2008 }
240    
241     Region::Region() {
242     pSample = NULL;
243     pInstrument = NULL;
244     loKey = hiKey = NONE;
245     minVel = maxVel = NONE;
246     startAddrsOffset = startAddrsCoarseOffset = endAddrsOffset = 0;
247     startloopAddrsOffset = endloopAddrsOffset = 0;
248     pan = fineTune = 0;
249    
250 iliev 2014 EG1PreAttackDelay = EG1Attack = EG1Hold = EG1Decay = EG1Release = ToSeconds(-12000);
251 iliev 2008 EG1Sustain = 0;
252 iliev 2014 EG2PreAttackDelay = EG2Attack = EG2Hold = EG2Decay = EG2Release = ToSeconds(-12000);
253     EG2Sustain = 0;
254 iliev 2008 }
255    
256     void Region::SetGenerator(sf2::File* pFile, GenList& Gen) {
257     switch(Gen.GenOper) {
258     case START_ADDRS_OFFSET:
259     startAddrsOffset = Gen.GenAmount.wAmount;
260     break;
261     case END_ADDRS_OFFSET:
262     if (Gen.GenAmount.shAmount <= 0) {
263     endAddrsOffset = Gen.GenAmount.shAmount;
264     } else {
265     std::cerr << "Ignoring invalid endAddrsOffset" << std::endl;
266     }
267     break;
268     case STARTLOOP_ADDRS_OFFSET:
269     startloopAddrsOffset = Gen.GenAmount.shAmount;
270     break;
271     case ENDLOOP_ADDRS_OFFSET:
272     endloopAddrsOffset = Gen.GenAmount.shAmount;
273     break;
274     case START_ADDRS_COARSE_OFFSET:
275     startAddrsCoarseOffset = Gen.GenAmount.wAmount;
276     break;
277     case MOD_LFO_TO_PITCH:
278     break;
279     case VIB_LFO_TO_PITCH:
280     break;
281     case MOD_ENV_TO_PITCH:
282     break;
283     case INITIAL_FILTER_FC:
284     break;
285     case INITIAL_FILTER_Q:
286     break;
287     case MOD_LFO_TO_FILTER_FC:
288     break;
289     case MOD_ENV_TO_FILTER_FC:
290     break;
291     case END_ADDRS_COARSE_OFFSET:
292     break;
293     case MOD_LFO_TO_VOLUME:
294     break;
295     case CHORUS_EFFECTS_SEND:
296     break;
297     case REVERB_EFFECTS_SEND:
298     break;
299     case PAN:
300     pan = Gen.GenAmount.shAmount;
301     pan * 64; pan /= 500;
302     if (pan < -64) pan = -64;
303     if (pan > 63) pan = 63;
304     break;
305     case DELAY_MOD_LFO:
306     break;
307     case FREQ_MOD_LFO:
308     break;
309     case DELAY_VIB_LFO:
310     break;
311     case FREQ_VIB_LFO:
312     break;
313     case DELAY_MOD_ENV:
314 iliev 2014 EG2PreAttackDelay = ToSeconds(Gen.GenAmount.shAmount);
315 iliev 2008 break;
316     case ATTACK_MOD_ENV:
317 iliev 2014 EG2Attack = ToSeconds(Gen.GenAmount.shAmount);
318 iliev 2008 break;
319     case HOLD_MOD_ENV:
320 iliev 2014 EG2Hold = ToSeconds(Gen.GenAmount.shAmount);
321 iliev 2008 break;
322     case DECAY_MOD_ENV:
323 iliev 2014 EG2Decay = ToSeconds(Gen.GenAmount.shAmount);
324 iliev 2008 break;
325     case SUSTAIN_MOD_ENV:
326 iliev 2014 EG2Sustain = 1000 - Gen.GenAmount.shAmount;
327 iliev 2008 break;
328     case RELEASEMODENV:
329 iliev 2014 EG2Release = ToSeconds(Gen.GenAmount.shAmount);
330 iliev 2008 break;
331     case KEYNUM_TO_MOD_ENV_HOLD:
332     break;
333     case KEYNUM_TO_MOD_ENV_DECAY:
334     break;
335     case DELAY_VOL_ENV:
336 iliev 2014 EG1PreAttackDelay = ToSeconds(Gen.GenAmount.shAmount);
337 iliev 2008 break;
338     case ATTACK_VOL_ENV:
339     EG1Attack = ToSeconds(Gen.GenAmount.shAmount);
340     break;
341     case HOLD_VOL_ENV:
342     EG1Hold = ToSeconds(Gen.GenAmount.shAmount);
343     break;
344     case DECAY_VOL_ENV:
345     EG1Decay = ToSeconds(Gen.GenAmount.shAmount);
346     break;
347     case SUSTAIN_VOL_ENV:
348 iliev 2014 EG1Sustain = ToPermilles(Gen.GenAmount.shAmount);
349 iliev 2008 break;
350     case RELEASE_VOL_ENV:
351     EG1Release = ToSeconds(Gen.GenAmount.shAmount);
352     break;
353     case KEYNUM_TO_VOL_ENV_HOLD:
354     break;
355     case KEYNUM_TO_VOL_ENV_DECAY:
356     break;
357     case INSTRUMENT: {
358     uint16_t id = Gen.GenAmount.wAmount;
359     if (id >= pFile->Instruments.size()) {
360     throw Exception("Broken SF2 file (missing instruments)");
361     }
362     pInstrument = pFile->Instruments[id];
363     break;
364     }
365     case KEY_RANGE:
366     loKey = Gen.GenAmount.ranges.byLo;
367     hiKey = Gen.GenAmount.ranges.byHi;
368     break;
369     case VEL_RANGE:
370     minVel = Gen.GenAmount.ranges.byLo;
371     maxVel = Gen.GenAmount.ranges.byHi;
372     break;
373     case STARTLOOP_ADDRS_COARSE_OFFSET:
374     break;
375     case KEYNUM:
376     break;
377     case VELOCITY:
378     break;
379     case INITIAL_ATTENUATION:
380     break;
381     case ENDLOOP_ADDRS_COARSE_OFFSET:
382     break;
383     case COARSE_TUNE:
384     break;
385     case FINE_TUNE:
386     fineTune = Gen.GenAmount.shAmount;
387     break;
388     case SAMPLE_ID: {
389     uint16_t sid = Gen.GenAmount.wAmount;
390     if (sid >= pFile->Samples.size()) {
391     throw Exception("Broken SF2 file (missing samples)");
392     }
393     pSample = pFile->Samples[sid];
394     break;
395     }
396     case SAMPLE_MODES:
397     break;
398     case SCALE_TUNING:
399     break;
400     case EXCLUSIVE_CLASS:
401     break;
402     case OVERRIDING_ROOT_KEY:
403     break;
404     }
405     }
406    
407     void Region::SetModulator(sf2::File* pFile, ModList& Mod) {
408     modulators.push_back(ModulatorItem(Mod));
409     /*switch(srcType) {
410     case NO_CONTROLLER:
411     break;
412     case NOTE_ON_VELOCITY:
413     break;
414     case NOTE_ON_KEY_NUMBER:
415     break;
416     case POLY_PRESSURE:
417     break;
418     case CHANNEL_PRESSURE:
419     break;
420     case PITCH_WHEEL:
421     break;
422     case PITCH_WHEEL_SENSITIVITY:
423     break;
424     case LINK:
425     break;
426     default: std::cout << "Unknown controller source: " << srcType << std::endl;
427     }*/
428     }
429    
430     InstrumentBase::InstrumentBase(sf2::File* pFile) {
431     this->pFile = pFile;
432     pGlobalRegion = NULL;
433     }
434    
435     InstrumentBase::~InstrumentBase() {
436     if (pGlobalRegion) delete pGlobalRegion;
437     for (int i = regions.size() - 1; i >= 0; i--) {
438     if (regions[i]) delete (regions[i]);
439     }
440     }
441    
442     int InstrumentBase::GetRegionCount() {
443     return regions.size() - 1; // exclude terminal region
444     }
445    
446     Region* InstrumentBase::GetRegion(int idx) {
447     if (idx < 0 || idx >= GetRegionCount()) {
448     throw Exception("Region index out of bounds");
449     }
450    
451     return regions[idx];
452     }
453    
454     std::vector<Region*> InstrumentBase::GetRegionsOnKey(int key, uint8_t vel) {
455     std::vector<Region*> v;
456     for (int i = 0; i < GetRegionCount(); i++) {
457     Region* r = GetRegion(i);
458     if (
459     key >= r->loKey && key <= r->hiKey &&
460     ((r->minVel == NONE && r->maxVel == NONE) || (vel >= r->minVel && vel <= r->maxVel))
461     ) {
462     v.push_back(r);
463     }
464     }
465    
466     return v;
467     }
468    
469     Instrument::Instrument(sf2::File* pFile, RIFF::Chunk* ck) : InstrumentBase(pFile) {
470     this->pFile = pFile;
471     LoadString(ck, Name, 20);
472     InstBagNdx = ck->ReadInt16();
473     }
474    
475     Instrument::~Instrument() {
476    
477     }
478    
479     void Instrument::LoadRegions(int idx1, int idx2) {
480     for (int i = idx1; i < idx2 - 1; i++) {
481     int gIdx1 = pFile->InstBags[i].InstGenNdx;
482     int gIdx2 = pFile->InstBags[i + 1].InstGenNdx;
483    
484     if (gIdx1 < 0 || gIdx2 < 0 || gIdx1 > gIdx2 || gIdx2 >= pFile->InstGenLists.size()) {
485     throw Exception("Broken SF2 file (invalid InstGenNdx)");
486     }
487    
488     int mIdx1 = pFile->InstBags[i].InstModNdx;
489     int mIdx2 = pFile->InstBags[i + 1].InstModNdx;
490    
491     if (mIdx1 < 0 || mIdx2 < 0 || mIdx1 > mIdx2 || mIdx2 >= pFile->InstModLists.size()) {
492     throw Exception("Broken SF2 file (invalid InstModNdx)");
493     }
494    
495     Region* reg = new Region;
496    
497     for (int j = gIdx1; j < gIdx2; j++) {
498     reg->SetGenerator(pFile, pFile->InstGenLists[j]);
499     // TODO: ignore generators following a sampleID generator
500     }
501    
502     for (int j = mIdx1; j < mIdx2; j++) {
503     reg->SetModulator(pFile, pFile->InstModLists[j]);
504     }
505    
506     if (reg->pSample == NULL) {
507     if (i == idx1) {
508     pGlobalRegion = reg; // global zone
509     } else {
510     std::cerr << "Ignoring instrument's region without sample" << std::endl;
511     delete reg;
512     }
513     } else {
514     regions.push_back(reg);
515     }
516     }
517     }
518    
519     Preset::Preset(sf2::File* pFile, RIFF::Chunk* ck): InstrumentBase(pFile) {
520     this->pFile = pFile;
521     LoadString(ck, Name, 20);
522     PresetNum = ck->ReadInt16();
523     Bank = ck->ReadInt16();
524     PresetBagNdx = ck->ReadInt16();
525     Library = ck->ReadInt32();
526     Genre = ck->ReadInt32();
527     Morphology = ck->ReadInt32();
528     }
529    
530     Preset::~Preset() {
531    
532     }
533    
534     void Preset::LoadRegions(int idx1, int idx2) {
535     for (int i = idx1; i < idx2 - 1; i++) {
536     int gIdx1 = pFile->PresetBags[i].GenNdx;
537     int gIdx2 = pFile->PresetBags[i + 1].GenNdx;
538    
539     if (gIdx1 < 0 || gIdx2 < 0 || gIdx1 > gIdx2 || gIdx2 >= pFile->PresetGenLists.size()) {
540     throw Exception("Broken SF2 file (invalid PresetGenNdx)");
541     }
542    
543     Region* reg = new Region;
544    
545     for (int j = gIdx1; j < gIdx2; j++) {
546     reg->SetGenerator(pFile, pFile->PresetGenLists[j]);
547     }
548     if (reg->pInstrument == NULL) {
549     if (i == idx1) {
550     pGlobalRegion = reg; // global zone
551     } else {
552     std::cerr << "Ignoring preset's region without instrument" << std::endl;
553     delete reg;
554     }
555     } else {
556     regions.push_back(reg);
557     }
558     }
559     }
560    
561     /** @brief Constructor.
562     *
563     * Load an existing SF2 file.
564     *
565     * @param pRIFF - pointer to a RIFF file which is actually the SF2 file
566     * to load
567     * @throws Exception if given file is not a SF2 file, expected chunks
568     * are missing
569     */
570     File::File(RIFF::File* pRIFF) {
571     if (!pRIFF) throw Exception("NULL pointer reference to RIFF::File object.");
572     this->pRIFF = pRIFF;
573    
574     if (pRIFF->GetListType() != RIFF_TYPE_SF2) {
575     throw Exception("Not a SF2 file");
576     }
577    
578     pInfo = new Info(pRIFF);
579     if (pInfo->pVer->Major != 2) {
580     throw Exception("Unsupported version: " + ToString(pInfo->pVer->Major));
581     }
582    
583     RIFF::List* lstSDTA = pRIFF->GetSubList(LIST_TYPE_SDTA);
584     if (lstSDTA == NULL) {
585     throw Exception("Broken SF2 file (missing sdta)");
586     }
587    
588     RIFF::Chunk* pCkSmpl = lstSDTA->GetSubChunk(CHUNK_ID_SMPL);
589     RIFF::Chunk* pCkSm24 = lstSDTA->GetSubChunk(CHUNK_ID_SM24);
590     if (pCkSmpl != NULL && pCkSm24 != NULL) {
591     long l = pCkSmpl->GetSize() / 2;
592     if (l%2) l++;
593     if (pCkSm24->GetSize() != l) {
594     pCkSm24 = NULL; // ignoring sm24 due to invalid size
595     }
596     }
597    
598     RIFF::List* lstPDTA = pRIFF->GetSubList(LIST_TYPE_PDTA);
599     if (lstPDTA == NULL) {
600     throw Exception("Broken SF2 file (missing pdta)");
601     }
602    
603     RIFF::Chunk* ck = lstPDTA->GetSubChunk(CHUNK_ID_PHDR);
604     if (ck->GetSize() < 38) {
605     throw Exception("Broken SF2 file (broken phdr)");
606     }
607    
608     int count = ck->GetSize() / 38;
609     for (int i = 0; i < count; i++) {
610     Presets.push_back(new Preset(this, ck));
611     }
612    
613     ck = GetMandatoryChunk(lstPDTA, CHUNK_ID_PBAG);
614     if (ck->GetSize() < 4 || (ck->GetSize() % 4)) {
615     throw Exception("Broken SF2 file (broken pbag)");
616     }
617    
618     count = ck->GetSize() / 4;
619     for (int i = 0; i < count; i++) {
620     PresetBag pb;
621     pb.GenNdx = ck->ReadInt16();
622     pb.ModNdx = ck->ReadInt16();
623     PresetBags.push_back(pb);
624     }
625     //std::cout << "Preset bags: " << PresetBags.size() << std::endl;
626    
627     ck = GetMandatoryChunk(lstPDTA, CHUNK_ID_PMOD);
628     if (ck->GetSize() % 10) {
629     throw Exception("Broken SF2 file (broken pmod)");
630     }
631    
632     count = ck->GetSize() / 10;
633     for (int i = 0; i < count; i++) {
634     ModList ml;
635     ml.ModSrcOper = ck->ReadInt16();
636     ml.ModDestOper = ck->ReadInt16();
637     ml.ModAmount = ck->ReadInt16();
638     ml.ModAmtSrcOper = ck->ReadInt16();
639     ml.ModTransOper = ck->ReadInt16();
640     PresetModLists.push_back(ml);
641     }
642 iliev 2014 //std::cout << "Preset mod lists: " << PresetModLists.size() << std::endl;
643 iliev 2008
644     ck = GetMandatoryChunk(lstPDTA, CHUNK_ID_PGEN);
645     if (ck->GetSize() < 4 || (ck->GetSize() % 4)) {
646     throw Exception("Broken SF2 file (broken pgen)");
647     }
648    
649     count = ck->GetSize() / 4;
650     for (int i = 0; i < count; i++) {
651     GenList gl;
652     gl.GenOper = ck->ReadInt16();
653     gl.GenAmount.wAmount = ck->ReadInt16();
654     PresetGenLists.push_back(gl);
655     }
656     //std::cout << "Preset gen lists: " << PresetGenLists.size() << std::endl;
657    
658     ck = GetMandatoryChunk(lstPDTA, CHUNK_ID_INST);
659     if (ck->GetSize() < (22 * 2) || (ck->GetSize() % 22)) {
660     throw Exception("Broken SF2 file (broken inst)");
661     }
662     count = ck->GetSize() / 22;
663     for (int i = 0; i < count; i++) {
664     Instruments.push_back(new Instrument(this, ck));
665     }
666    
667     ck = GetMandatoryChunk(lstPDTA, CHUNK_ID_IBAG);
668     if (ck->GetSize() < 4 || (ck->GetSize() % 4)) {
669     throw Exception("Broken SF2 file (broken ibag)");
670     }
671    
672     count = ck->GetSize() / 4;
673     for (int i = 0; i < count; i++) {
674     InstBag ib;
675     ib.InstGenNdx = ck->ReadInt16();
676     ib.InstModNdx = ck->ReadInt16();
677     InstBags.push_back(ib);
678     }
679     //std::cout << "Instrument bags: " << InstBags.size() << std::endl;
680    
681     ck = GetMandatoryChunk(lstPDTA, CHUNK_ID_IMOD);
682     if (ck->GetSize() % 10) {
683     throw Exception("Broken SF2 file (broken imod)");
684     }
685    
686     count = ck->GetSize() / 10;
687     for (int i = 0; i < count; i++) {
688     ModList ml;
689     ml.ModSrcOper = ck->ReadInt16();
690     ml.ModDestOper = ck->ReadInt16();
691     ml.ModAmount = ck->ReadInt16();
692     ml.ModAmtSrcOper = ck->ReadInt16();
693     ml.ModTransOper = ck->ReadInt16();
694     InstModLists.push_back(ml);
695     }
696 iliev 2014 //std::cout << "Instrument mod lists: " << InstModLists.size() << std::endl;
697 iliev 2008
698     ck = GetMandatoryChunk(lstPDTA, CHUNK_ID_IGEN);
699     if (ck->GetSize() < 4 || (ck->GetSize() % 4)) {
700     throw Exception("Broken SF2 file (broken igen)");
701     }
702    
703     count = ck->GetSize() / 4;
704     for (int i = 0; i < count; i++) {
705     GenList gl;
706     gl.GenOper = ck->ReadInt16();
707     gl.GenAmount.wAmount = ck->ReadInt16();
708     InstGenLists.push_back(gl);
709     }
710     //std::cout << "Instrument gen lists: " << InstGenLists.size() << std::endl;
711    
712     ck = GetMandatoryChunk(lstPDTA, CHUNK_ID_SHDR);
713     if ((ck->GetSize() % 46)) {
714     throw Exception("Broken SF2 file (broken shdr)");
715     }
716     count = ck->GetSize() / 46;
717     for (int i = 0; i < count; i++) {
718     Samples.push_back(new Sample(ck, pCkSmpl, pCkSm24));
719     }
720    
721     // Loading instrument regions
722     for (int i = 0; i < Instruments.size() - 1; i++) {
723     Instrument* instr = Instruments[i];
724     int x1 = instr->InstBagNdx;
725     int x2 = Instruments[i + 1]->InstBagNdx;
726     if (x1 < 0 || x2 < 0 || x1 > x2 || x2 >= InstBags.size()) {
727     throw Exception("Broken SF2 file (invalid InstBagNdx)");
728     }
729    
730     instr->LoadRegions(x1, x2);
731     }
732    
733     // Loading preset regions
734     for (int i = 0; i < Presets.size() - 1; i++) {
735     Preset* preset = Presets[i];
736     int x1 = preset->PresetBagNdx;
737     int x2 = Presets[i + 1]->PresetBagNdx;
738     if (x1 < 0 || x2 < 0 || x1 > x2 || x2 >= PresetBags.size()) {
739     throw Exception("Broken SF2 file (invalid PresetBagNdx)");
740     }
741    
742     preset->LoadRegions(x1, x2);
743     }
744     }
745    
746     File::~File() {
747     delete pInfo;
748     for (int i = Presets.size() - 1; i >= 0; i--) {
749     if (Presets[i]) delete (Presets[i]);
750     }
751     for (int i = Instruments.size() - 1; i >= 0; i--) {
752     if (Instruments[i]) delete (Instruments[i]);
753     }
754     for (int i = Samples.size() - 1; i >= 0; i--) {
755     if (Samples[i]) delete (Samples[i]);
756     }
757     }
758    
759     int File::GetPresetCount() {
760     return Presets.size() - 1; // exclude terminal preset (EOP)
761     }
762    
763     Preset* File::GetPreset(int idx) {
764     if (idx < 0 || idx >= GetPresetCount()) {
765     throw Exception("Preset index out of bounds");
766     }
767    
768     return Presets[idx];
769     }
770    
771     int File::GetInstrumentCount() {
772     return Instruments.size() - 1; // exclude terminal instrument (EOI)
773     }
774    
775     Instrument* File::GetInstrument(int idx) {
776     if (idx < 0 || idx >= GetInstrumentCount()) {
777     throw Exception("Instrument index out of bounds");
778     }
779    
780     return Instruments[idx];
781     }
782    
783     int File::GetSampleCount() {
784     return Samples.size() - 1; // exclude terminal sample (EOS)
785     }
786    
787     Sample* File::GetSample(int idx) {
788     if (idx < 0 || idx >= GetSampleCount()) {
789     throw Exception("Sample index out of bounds");
790     }
791    
792     return Samples[idx];
793     }
794    
795     void File::DeleteSample(Sample* pSample) {
796     for (int i = 0; i < GetSampleCount(); i++) {
797     if (Samples[i] == pSample) {
798     delete pSample;
799     Samples[i] = NULL;
800     return;
801     }
802     }
803    
804     throw Exception("Unknown sample: " + pSample->Name);
805     }
806    
807     bool File::HasSamples() {
808     for (int i = 0; i < GetSampleCount(); i++) {
809     if (Samples[i] != NULL) return true;
810     }
811    
812     return false;
813     }
814    
815     /**
816     * Loads the whole sample wave into RAM. Use
817     * ReleaseSampleData() to free the memory if you don't need the cached
818     * sample data anymore.
819     *
820     * @returns buffer_t structure with start address and size of the buffer
821     * in bytes
822     * @see ReleaseSampleData(), Read(), SetPos()
823     */
824     Sample::buffer_t Sample::LoadSampleData() {
825     return LoadSampleDataWithNullSamplesExtension(GetTotalFrameCount(), 0); // 0 amount of NullSamples
826     }
827    
828     /**
829     * Reads and caches the first \a SampleCount
830     * numbers of SamplePoints in RAM. Use ReleaseSampleData() to free the
831     * memory space if you don't need the cached samples anymore.
832     * Read the <i>Size</i> member of the <i>buffer_t</i> structure
833     * that will be returned to determine the actual cached samples, but note
834     * that the size is given in bytes! You get the number of actually cached
835     * samples by dividing it by the frame size of the sample:
836     * @code
837     * buffer_t buf = pSample->LoadSampleData(acquired_samples);
838     * long cachedsamples = buf.Size / pSample->FrameSize;
839     * @endcode
840     *
841     * @param SampleCount - number of sample points to load into RAM
842     * @returns buffer_t structure with start address and size of
843     * the cached sample data in bytes
844     * @see ReleaseSampleData(), Read(), SetPos()
845     */
846     Sample::buffer_t Sample::LoadSampleData(unsigned long SampleCount) {
847     return LoadSampleDataWithNullSamplesExtension(SampleCount, 0); // 0 amount of NullSamples
848     }
849    
850     /**
851     * Loads the whole sample wave into RAM. Use
852     * ReleaseSampleData() to free the memory if you don't need the cached
853     * sample data anymore.
854     * The method will add \a NullSamplesCount silence samples past the
855     * official buffer end (this won't affect the 'Size' member of the
856     * buffer_t structure, that means 'Size' always reflects the size of the
857     * actual sample data, the buffer might be bigger though). Silence
858     * samples past the official buffer are needed for differential
859     * algorithms that always have to take subsequent samples into account
860     * (resampling/interpolation would be an important example) and avoids
861     * memory access faults in such cases.
862     *
863     * @param NullSamplesCount - number of silence samples the buffer should
864     * be extended past it's data end
865     * @returns buffer_t structure with start address and
866     * size of the buffer in bytes
867     * @see ReleaseSampleData(), Read(), SetPos()
868     */
869     Sample::buffer_t Sample::LoadSampleDataWithNullSamplesExtension(uint NullSamplesCount) {
870     return LoadSampleDataWithNullSamplesExtension(GetTotalFrameCount(), NullSamplesCount);
871     }
872    
873     /**
874     * Reads and caches the first \a SampleCount
875     * numbers of SamplePoints in RAM. Use ReleaseSampleData() to free the
876     * memory space if you don't need the cached samples anymore.
877     * Read the <i>Size</i> member of the <i>buffer_t</i> structure
878     * that will be returned to determine the actual cached samples, but note
879     * that the size is given in bytes! You get the number of actually cached
880     * samples by dividing it by the frame size of the sample:
881     * @code
882     * buffer_t buf = pSample->LoadSampleDataWithNullSamplesExtension(acquired_samples, null_samples);
883     * long cachedsamples = buf.Size / pSample->FrameSize;
884     * @endcode
885     * The method will add \a NullSamplesCount silence samples past the
886     * official buffer end (this won't affect the 'Size' member of the
887     * buffer_t structure, that means 'Size' always reflects the size of the
888     * actual sample data, the buffer might be bigger though). Silence
889     * samples past the official buffer are needed for differential
890     * algorithms that always have to take subsequent samples into account
891     * (resampling/interpolation would be an important example) and avoids
892     * memory access faults in such cases.
893     *
894     * @param SampleCount - number of sample points to load into RAM
895     * @param NullSamplesCount - number of silence samples the buffer should
896     * be extended past it's data end
897     * @returns buffer_t structure with start address and
898     * size of the cached sample data in bytes
899     * @see ReleaseSampleData(), Read(), SetPos()
900     */
901     Sample::buffer_t Sample::LoadSampleDataWithNullSamplesExtension(unsigned long SampleCount, uint NullSamplesCount) {
902     if (SampleCount > GetTotalFrameCount()) SampleCount = GetTotalFrameCount();
903     if (RAMCache.pStart) delete[] (int8_t*) RAMCache.pStart;
904     unsigned long allocationsize = (SampleCount + NullSamplesCount) * GetFrameSize();
905     SetPos(0); // reset read position to begin of sample
906     RAMCache.pStart = new int8_t[allocationsize];
907     RAMCache.Size = Read(RAMCache.pStart, SampleCount) * GetFrameSize();
908     RAMCache.NullExtensionSize = allocationsize - RAMCache.Size;
909     // fill the remaining buffer space with silence samples
910     memset((int8_t*)RAMCache.pStart + RAMCache.Size, 0, RAMCache.NullExtensionSize);
911     return GetCache();
912     }
913    
914     /**
915     * Returns current cached sample points. A buffer_t structure will be
916     * returned which contains address pointer to the begin of the cache and
917     * the size of the cached sample data in bytes. Use
918     * <i>LoadSampleData()</i> to cache a specific amount of sample points in
919     * RAM.
920     *
921     * @returns buffer_t structure with current cached sample points
922     * @see LoadSampleData();
923     */
924     Sample::buffer_t Sample::GetCache() {
925     // return a copy of the buffer_t structure
926     buffer_t result;
927     result.Size = this->RAMCache.Size;
928     result.pStart = this->RAMCache.pStart;
929     result.NullExtensionSize = this->RAMCache.NullExtensionSize;
930     return result;
931     }
932    
933     /**
934     * Frees the cached sample from RAM if loaded with
935     * <i>LoadSampleData()</i> previously.
936     *
937     * @see LoadSampleData();
938     */
939     void Sample::ReleaseSampleData() {
940     if (RAMCache.pStart) delete[] (int8_t*) RAMCache.pStart;
941     RAMCache.pStart = NULL;
942     RAMCache.Size = 0;
943     RAMCache.NullExtensionSize = 0;
944     }
945    
946     /**
947     * Sets the position within the sample (in sample points, not in
948     * bytes). Use this method and <i>Read()</i> if you don't want to load
949     * the sample into RAM, thus for disk streaming.
950     *
951     * @param SampleCount number of sample points to jump
952     * @returns the new sample position
953     * @see Read()
954     */
955     unsigned long Sample::SetPos(unsigned long SampleCount) {
956     pCkSmpl->SetPos((Start * 2) + (SampleCount * 2), RIFF::stream_start);
957     if(pCkSm24) pCkSm24->SetPos(Start + SampleCount, RIFF::stream_start);
958     return SampleCount;
959     }
960    
961     /**
962     * Returns the current position in the sample (in sample points).
963     */
964     unsigned long Sample::GetPos() {
965     return (pCkSmpl->GetPos() - (Start * 2)) / 2;
966     }
967    
968     /**
969     * Reads \a SampleCount number of sample points from the current
970     * position into the buffer pointed by \a pBuffer and increments the
971     * position within the sample. Use this method
972     * and <i>SetPos()</i> if you don't want to load the sample into RAM,
973     * thus for disk streaming.
974     *
975     * For 16 bit samples, the data in the buffer will be int16_t
976     * (using native endianness). For 24 bit, the buffer will
977     * contain three bytes per sample, little-endian.
978     *
979     * @param pBuffer destination buffer
980     * @param SampleCount number of sample points to read
981     * @returns number of successfully read sample points
982     * @see SetPos()
983     */
984     unsigned long Sample::Read(void* pBuffer, unsigned long SampleCount) {
985     if (SampleCount == 0) return 0;
986     long pos = GetPos();
987     if (pos + SampleCount > GetTotalFrameCount()) SampleCount = GetTotalFrameCount() - pos;
988    
989     if (GetFrameSize() / GetChannelCount() == 3 /* 24 bit */) {
990     uint8_t* pBuf = (uint8_t*)pBuffer;
991     if (SampleType == MONO_SAMPLE || SampleType == ROM_MONO_SAMPLE) {
992     for (int i = 0; i < SampleCount; i++) {
993     pBuf[i*3] = pCkSmpl->ReadInt16();
994     pBuf[i*3 + 2] = pCkSm24->ReadInt8();
995     }
996     } else if (SampleType == LEFT_SAMPLE || SampleType == ROM_LEFT_SAMPLE) {
997     for (int i = 0; i < SampleCount; i++) {
998     pBuf[i*6] = pCkSmpl->ReadInt16();
999     pBuf[i*6 + 2] = pCkSm24->ReadInt8();
1000     pBuf[i*6 + 3] = pBuf[i*6 + 4] = pBuf[i*6 + 5] = 0;
1001     }
1002     } else if (SampleType == RIGHT_SAMPLE || SampleType == ROM_RIGHT_SAMPLE) {
1003     for (int i = 0; i < SampleCount; i++) {
1004     pBuf[i*6] = pBuf[i*6 + 1] = pBuf[i*6 + 2] = 0;
1005     pBuf[i*6 + 3] = pCkSmpl->ReadInt16();
1006     pBuf[i*6 + 5] = pCkSm24->ReadInt8();
1007     }
1008     }
1009     } else {
1010     if (SampleType == MONO_SAMPLE || SampleType == ROM_MONO_SAMPLE) {
1011     return pCkSmpl->Read(pBuffer, SampleCount, 2);
1012     }
1013    
1014     int16_t* pBuf = (int16_t*)pBuffer;
1015     if (SampleType == LEFT_SAMPLE || SampleType == ROM_LEFT_SAMPLE) {
1016     pCkSmpl->Read(pBuf, SampleCount, 2);
1017     for (int i = SampleCount - 1; i >= 0; i--) {
1018     pBuf[i*2] = pBuf[i];
1019     pBuf[i*2 + 1] = 0;
1020     }
1021     } else if (SampleType == RIGHT_SAMPLE || SampleType == ROM_RIGHT_SAMPLE) {
1022     pCkSmpl->Read(pBuf, SampleCount, 2);
1023     for (int i = SampleCount - 1; i >= 0; i--) {
1024     pBuf[i*2] = 0;
1025     pBuf[i*2 + 1] = pBuf[i];
1026     }
1027     }
1028     }
1029    
1030     if (pCkSmpl->GetPos() > (End * 2)) {
1031     std::cerr << "Read after the sample end. This is a BUG!" << std::endl;
1032     std::cerr << "Current position: " << GetPos() << std::endl;
1033     std::cerr << "Total number of frames: " << GetTotalFrameCount() << std::endl << std::endl;
1034     }
1035     return SampleCount;
1036     }
1037    
1038    
1039     // *************** functions ***************
1040     // *
1041    
1042     /**
1043     * Returns the name of this C++ library.
1044     */
1045     String libraryName() {
1046     return PACKAGE;
1047     }
1048    
1049     /**
1050     * Returns version of this C++ library.
1051     */
1052     String libraryVersion() {
1053     return VERSION;
1054     }
1055    
1056     } // namespace sf2

  ViewVC Help
Powered by ViewVC