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

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

Parent Directory Parent Directory | Revision Log Revision Log


Revision 2044 - (show annotations) (download)
Sun Jan 10 12:58:51 2010 UTC (9 years, 8 months ago) by persson
File size: 55264 byte(s)
* sf2: fixes for big endian systems
* removed compiler warnings

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

  ViewVC Help
Powered by ViewVC