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

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

Parent Directory Parent Directory | Revision Log Revision Log


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

1 /***************************************************************************
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