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

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

Parent Directory Parent Directory | Revision Log Revision Log


Revision 2026 - (show annotations) (download)
Tue Nov 3 19:08:44 2009 UTC (10 years, 9 months ago) by iliev
File size: 55387 byte(s)
* sf2: better support for preset regions

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

  ViewVC Help
Powered by ViewVC