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

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

Parent Directory Parent Directory | Revision Log Revision Log


Revision 2100 - (show annotations) (download)
Sun May 30 11:39:36 2010 UTC (13 years, 10 months ago) by persson
File size: 55227 byte(s)
* sf2: changed region lookup API to avoid malloc in RT threads

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

  ViewVC Help
Powered by ViewVC