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

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

Parent Directory Parent Directory | Revision Log Revision Log


Revision 2008 - (hide annotations) (download)
Fri Oct 23 16:56:16 2009 UTC (14 years, 6 months ago) by iliev
File size: 38365 byte(s)
* Initial CVS Import

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

  ViewVC Help
Powered by ViewVC