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

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

Parent Directory Parent Directory | Revision Log Revision Log


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

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.000577789506555
35 #define _200TH_ROOT_OF_10 1.011579454259899
36
37 namespace sf2 {
38 double ToSeconds(int Timecents) {
39 if (Timecents == 0) return 1.0;
40 if (Timecents == -32768) return 0.0;
41 return pow(_1200TH_ROOT_OF_2, Timecents);
42 }
43
44 double ToPermilles(int Centibels) {
45 if (Centibels == 0) return 1000.0;
46 if (Centibels < 0) return 0.0;
47 return pow(_200TH_ROOT_OF_10, Centibels);
48 }
49
50 RIFF::Chunk* GetMandatoryChunk(RIFF::List* list, uint32_t chunkId) {
51 RIFF::Chunk* ck = list->GetSubChunk(chunkId);
52 if(ck == NULL) throw Exception("Mandatory chunk in RIFF list chunk not found: " + ToString(chunkId));
53 return ck;
54 }
55
56 void LoadString(RIFF::Chunk* ck, std::string& s, int strLength) {
57 if(ck == NULL) return;
58 char* buf = new char[strLength];
59 int len = 0;
60 for(int i = 0; i < strLength; i++) {
61 buf[i] = ck->ReadInt8();
62 if(buf[i] == 0 && !len) len = i;
63 }
64 if(!len) len = strLength;
65 s.assign(buf, len);
66 delete [] buf;
67 }
68
69 /**
70 * Throws an error if the chunk is NULL or
71 * the chunk data size is less than size (in bytes).
72 */
73 void VerifySize(RIFF::Chunk* ck, int size) {
74 if (ck == NULL) throw Exception("NULL chunk");
75 if (ck->GetSize() < size) {
76 throw Exception("Invalid chunk size. Chunk ID: " + ToString(ck->GetChunkID()));
77 }
78 }
79
80 Modulator::Modulator(SFModulator mod) {
81 Type = mod >> 10; // The last 6 bits
82 Polarity = mod & (1 << 9);
83 Direction = mod & (1 << 8);
84 MidiPalete = mod & (1 << 7); // two paletes - general or MIDI
85 Index = mod & 0x7f; /* index field */;
86
87 }
88
89 ModulatorItem::ModulatorItem(ModList& mod) :
90 ModSrcOper(Modulator(mod.ModSrcOper)),
91 ModAmtSrcOper(Modulator(mod.ModAmtSrcOper))
92 {
93
94 }
95
96 Version::Version(RIFF::Chunk* ck) {
97 if(ck != NULL) VerifySize(ck, 4);
98 Major = ck ? ck->ReadUint16() : 0;
99 Minor = ck ? ck->ReadUint16() : 0;
100 }
101
102 // *************** Info ***************
103 // *
104
105 /** @brief Constructor.
106 *
107 * Initializes the info strings with values provided by an INFO list chunk.
108 *
109 * @param list - pointer to a list chunk which contains an INFO list chunk
110 */
111 Info::Info(RIFF::List* list) {
112 if (list) {
113 RIFF::List* lstINFO = list->GetSubList(LIST_TYPE_INFO);
114 if (lstINFO) {
115 pVer = new Version(GetMandatoryChunk(lstINFO, CHUNK_ID_IFIL));
116 LoadString(CHUNK_ID_ISNG, lstINFO, SoundEngine);
117 LoadString(CHUNK_ID_INAM, lstINFO, BankName);
118 LoadString(CHUNK_ID_IROM, lstINFO, RomName);
119 pRomVer = new Version(lstINFO->GetSubChunk(CHUNK_ID_IVER));
120 LoadString(CHUNK_ID_ICRD, lstINFO, CreationDate);
121 LoadString(CHUNK_ID_IENG, lstINFO, Engineers);
122 LoadString(CHUNK_ID_IPRD, lstINFO, Product);
123 LoadString(CHUNK_ID_ICOP, lstINFO, Copyright);
124 LoadString(CHUNK_ID_ICMT, lstINFO, Comments);
125 LoadString(CHUNK_ID_ISFT, lstINFO, Software);
126
127 }
128 }
129 }
130
131 Info::~Info() {
132 delete pVer;
133 delete pRomVer;
134 }
135
136 /** @brief Load given INFO field.
137 *
138 * Load INFO field from INFO chunk with chunk ID \a ChunkID from INFO
139 * list chunk \a lstINFO and save value to \a s.
140 */
141 void Info::LoadString(uint32_t ChunkID, RIFF::List* lstINFO, String& s) {
142 RIFF::Chunk* ck = lstINFO->GetSubChunk(ChunkID);
143 ::LoadString(ck, s); // function from helper.h
144 }
145
146 Sample::Sample(RIFF::Chunk* ck, RIFF::Chunk* pCkSmpl, RIFF::Chunk* pCkSm24) {
147 this->pCkSmpl = pCkSmpl;
148 this->pCkSm24 = pCkSm24;
149
150 LoadString(ck, Name, 20);
151 Start = ck->ReadInt32();
152 End = ck->ReadInt32();
153 StartLoop = ck->ReadInt32();
154 EndLoop = ck->ReadInt32();
155 SampleRate = ck->ReadInt32();
156 OriginalPitch = ck->ReadInt8();
157 PitchCorrection = ck->ReadInt8();
158 SampleLink = ck->ReadInt16();
159 SampleType = ck->ReadInt16();
160
161 if (Start > End || !pCkSmpl || pCkSmpl->GetSize() <= End) {
162 throw Exception("Broken SF2 file (invalid sample info)");
163 }
164
165 ChannelCount = 1;
166 switch(SampleType) {
167 case 0 : // terminal sample
168 case sf2::Sample::MONO_SAMPLE :
169 case sf2::Sample::ROM_MONO_SAMPLE : break;
170 case sf2::Sample::RIGHT_SAMPLE :
171 case sf2::Sample::LEFT_SAMPLE :
172 case sf2::Sample::ROM_RIGHT_SAMPLE :
173 case sf2::Sample::ROM_LEFT_SAMPLE : ChannelCount = 2; break;
174 case sf2::Sample::LINKED_SAMPLE :
175 case sf2::Sample::ROM_LINKED_SAMPLE : std::cerr << "Linked samples not implemented yet"; break;
176 default: throw Exception("Broken SF2 file (invalid sample type)");
177 }
178
179 RAMCache.Size = 0;
180 RAMCache.pStart = NULL;
181 RAMCache.NullExtensionSize = 0;
182 }
183
184 int Sample::GetChannelCount() {
185 return ChannelCount;
186 }
187
188 long Sample::GetTotalFrameCount() {
189 return (End - Start);
190 }
191
192 /**
193 * @returns The frame size in bytes
194 */
195 int Sample::GetFrameSize() {
196 return ChannelCount * ((pCkSm24 != NULL) ? 3 : 2);
197 }
198
199 bool Sample::HasLoops() {
200 return StartLoop != 0 && EndLoop != 0;
201 }
202
203 /**
204 * Reads \a SampleCount number of sample points from the position stored
205 * in \a pPlaybackState into the buffer pointed by \a pBuffer and moves
206 * the position within the sample respectively, this method honors the
207 * looping informations of the sample (if any). Use this
208 * method if you don't want to load the sample into RAM, thus for disk
209 * streaming. All this methods needs to know to proceed with streaming
210 * for the next time you call this method is stored in \a pPlaybackState.
211 * You have to allocate and initialize the playback_state_t structure by
212 * yourself before you use it to stream a sample:
213 * @code
214 * PlaybackState playbackstate;
215 * playbackstate.position = 0;
216 * playbackstate.reverse = false;
217 * playbackstate.loop_cycles_left = pSample->LoopPlayCount;
218 * @endcode
219 * You don't have to take care of things like if there is actually a loop
220 * defined or if the current read position is located within a loop area.
221 * The method already handles such cases by itself.
222 *
223 * @param pBuffer destination buffer
224 * @param FrameCount number of sample points to read
225 * @param pPlaybackState will be used to store and reload the playback
226 * state for the next ReadAndLoop() call
227 * @returns number of successfully read sample points
228 */
229 unsigned long Sample::ReadAndLoop (
230 void* pBuffer,
231 unsigned long FrameCount,
232 PlaybackState* pPlaybackState
233 ) {
234 SetPos(pPlaybackState->position);
235 long frames = Read(pBuffer, FrameCount);
236 pPlaybackState->position = GetPos();
237 // TODO: Implement looping
238 return frames;
239 }
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 EG1PreAttackDelay = EG1Attack = EG1Hold = EG1Decay = EG1Release = ToSeconds(-12000);
251 EG1Sustain = 0;
252 EG2PreAttackDelay = EG2Attack = EG2Hold = EG2Decay = EG2Release = ToSeconds(-12000);
253 EG2Sustain = 0;
254 }
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 EG2PreAttackDelay = ToSeconds(Gen.GenAmount.shAmount);
315 break;
316 case ATTACK_MOD_ENV:
317 EG2Attack = ToSeconds(Gen.GenAmount.shAmount);
318 break;
319 case HOLD_MOD_ENV:
320 EG2Hold = ToSeconds(Gen.GenAmount.shAmount);
321 break;
322 case DECAY_MOD_ENV:
323 EG2Decay = ToSeconds(Gen.GenAmount.shAmount);
324 break;
325 case SUSTAIN_MOD_ENV:
326 EG2Sustain = 1000 - Gen.GenAmount.shAmount;
327 break;
328 case RELEASEMODENV:
329 EG2Release = ToSeconds(Gen.GenAmount.shAmount);
330 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 EG1PreAttackDelay = ToSeconds(Gen.GenAmount.shAmount);
337 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 EG1Sustain = ToPermilles(Gen.GenAmount.shAmount);
349 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 //std::cout << "Preset mod lists: " << PresetModLists.size() << std::endl;
643
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 //std::cout << "Instrument mod lists: " << InstModLists.size() << std::endl;
697
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