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

Annotation of /libgig/trunk/src/DLS.cpp

Parent Directory Parent Directory | Revision Log Revision Log


Revision 384 - (hide annotations) (download)
Thu Feb 17 02:22:26 2005 UTC (19 years, 1 month ago) by schoenebeck
File size: 20952 byte(s)
* gig::Sample: external decompression buffers can now be used for streaming
  with Read() and ReadAndLoop() to avoid race conditions in case of
  multiple streaming threads
* fixed some memory leaks caused by non virtual base constructors

1 schoenebeck 2 /***************************************************************************
2     * *
3     * libgig - C++ cross-platform Gigasampler format file loader library *
4     * *
5 schoenebeck 384 * Copyright (C) 2003-2005 by Christian Schoenebeck *
6     * <cuse@users.sourceforge.net> *
7 schoenebeck 2 * *
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 "DLS.h"
25    
26     namespace DLS {
27    
28     // *************** Connection ***************
29     // *
30    
31     void Connection::Init(conn_block_t* Header) {
32     Source = (conn_src_t) Header->source;
33     Control = (conn_src_t) Header->control;
34     Destination = (conn_dst_t) Header->destination;
35     Scale = Header->scale;
36     SourceTransform = (conn_trn_t) CONN_TRANSFORM_SRC(Header->transform);
37     ControlTransform = (conn_trn_t) CONN_TRANSFORM_CTL(Header->transform);
38     DestinationTransform = (conn_trn_t) CONN_TRANSFORM_DST(Header->transform);
39     SourceInvert = CONN_TRANSFORM_INVERT_SRC(Header->transform);
40     SourceBipolar = CONN_TRANSFORM_BIPOLAR_SRC(Header->transform);
41     ControlInvert = CONN_TRANSFORM_INVERT_CTL(Header->transform);
42     ControlBipolar = CONN_TRANSFORM_BIPOLAR_CTL(Header->transform);
43     }
44    
45    
46    
47     // *************** Articulation ***************
48     // *
49    
50     Articulation::Articulation(RIFF::List* artList) {
51     if (artList->GetListType() != LIST_TYPE_ART2 &&
52     artList->GetListType() != LIST_TYPE_ART1) {
53     throw DLS::Exception("<art1-list> or <art2-list> chunk expected");
54     }
55     uint32_t headerSize = artList->ReadUint32();
56     Connections = artList->ReadUint32();
57     artList->SetPos(headerSize);
58    
59     pConnections = new Connection[Connections];
60     Connection::conn_block_t connblock;
61     for (uint32_t i = 0; i <= Connections; i++) {
62 schoenebeck 11 artList->Read(&connblock.source, 1, 2);
63     artList->Read(&connblock.control, 1, 2);
64     artList->Read(&connblock.destination, 1, 2);
65     artList->Read(&connblock.transform, 1, 2);
66     artList->Read(&connblock.scale, 1, 4);
67 schoenebeck 2 pConnections[i].Init(&connblock);
68     }
69     }
70    
71     Articulation::~Articulation() {
72     if (pConnections) delete[] pConnections;
73     }
74    
75    
76    
77     // *************** Articulator ***************
78     // *
79    
80     Articulator::Articulator(RIFF::List* ParentList) {
81     pParentList = ParentList;
82     pArticulations = NULL;
83     }
84    
85     Articulation* Articulator::GetFirstArticulation() {
86     if (!pArticulations) LoadArticulations();
87     if (!pArticulations) return NULL;
88     ArticulationsIterator = pArticulations->begin();
89     return (ArticulationsIterator != pArticulations->end()) ? *ArticulationsIterator : NULL;
90     }
91    
92     Articulation* Articulator::GetNextArticulation() {
93     if (!pArticulations) return NULL;
94     ArticulationsIterator++;
95     return (ArticulationsIterator != pArticulations->end()) ? *ArticulationsIterator : NULL;
96     }
97    
98     void Articulator::LoadArticulations() {
99     // prefer articulation level 2
100     RIFF::List* lart = pParentList->GetSubList(LIST_TYPE_LAR2);
101     if (!lart) lart = pParentList->GetSubList(LIST_TYPE_LART);
102     if (lart) {
103     uint32_t artCkType = (lart->GetListType() == LIST_TYPE_LAR2) ? LIST_TYPE_ART2
104     : LIST_TYPE_ART1;
105     RIFF::List* art = lart->GetFirstSubList();
106     while (art) {
107     if (art->GetListType() == artCkType) {
108     if (!pArticulations) pArticulations = new ArticulationList;
109     pArticulations->push_back(new Articulation(art));
110     }
111     art = lart->GetNextSubList();
112     }
113     }
114     }
115    
116     Articulator::~Articulator() {
117     if (pArticulations) {
118     ArticulationList::iterator iter = pArticulations->begin();
119     ArticulationList::iterator end = pArticulations->end();
120     while (iter != end) {
121     delete *iter;
122     iter++;
123     }
124     delete pArticulations;
125     }
126     }
127    
128    
129    
130     // *************** Info ***************
131     // *
132    
133     Info::Info(RIFF::List* list) {
134     if (list) {
135     RIFF::List* lstINFO = list->GetSubList(LIST_TYPE_INFO);
136     if (lstINFO) {
137     LoadString(CHUNK_ID_INAM, lstINFO, Name);
138     LoadString(CHUNK_ID_IARL, lstINFO, ArchivalLocation);
139     LoadString(CHUNK_ID_ICRD, lstINFO, CreationDate);
140     LoadString(CHUNK_ID_ICMT, lstINFO, Comments);
141     LoadString(CHUNK_ID_IPRD, lstINFO, Product);
142     LoadString(CHUNK_ID_ICOP, lstINFO, Copyright);
143     LoadString(CHUNK_ID_IART, lstINFO, Artists);
144     LoadString(CHUNK_ID_IGNR, lstINFO, Genre);
145     LoadString(CHUNK_ID_IKEY, lstINFO, Keywords);
146     LoadString(CHUNK_ID_IENG, lstINFO, Engineer);
147     LoadString(CHUNK_ID_ITCH, lstINFO, Technician);
148     LoadString(CHUNK_ID_ISFT, lstINFO, Software);
149     LoadString(CHUNK_ID_IMED, lstINFO, Medium);
150     LoadString(CHUNK_ID_ISRC, lstINFO, Source);
151     LoadString(CHUNK_ID_ISRF, lstINFO, SourceForm);
152     LoadString(CHUNK_ID_ICMS, lstINFO, Commissioned);
153     }
154     }
155     }
156    
157    
158    
159     // *************** Resource ***************
160     // *
161    
162     Resource::Resource(Resource* Parent, RIFF::List* lstResource) {
163     pParent = Parent;
164    
165     pInfo = new Info(lstResource);
166    
167     RIFF::Chunk* ckDLSID = lstResource->GetSubChunk(CHUNK_ID_DLID);
168     if (ckDLSID) {
169     pDLSID = new dlsid_t;
170 schoenebeck 11 ckDLSID->Read(&pDLSID->ulData1, 1, 4);
171     ckDLSID->Read(&pDLSID->usData2, 1, 2);
172     ckDLSID->Read(&pDLSID->usData3, 1, 2);
173     ckDLSID->Read(pDLSID->abData, 8, 1);
174 schoenebeck 2 }
175     else pDLSID = NULL;
176     }
177    
178     Resource::~Resource() {
179     if (pDLSID) delete pDLSID;
180     if (pInfo) delete pInfo;
181     }
182    
183    
184    
185     // *************** Sampler ***************
186     // *
187    
188     Sampler::Sampler(RIFF::List* ParentList) {
189     RIFF::Chunk* wsmp = ParentList->GetSubChunk(CHUNK_ID_WSMP);
190     if (!wsmp) throw DLS::Exception("Mandatory <wsmp> chunk not found.");
191     uint32_t headersize = wsmp->ReadUint32();
192     UnityNote = wsmp->ReadUint16();
193     FineTune = wsmp->ReadInt16();
194     Gain = wsmp->ReadInt32();
195     SamplerOptions = wsmp->ReadUint32();
196     NoSampleDepthTruncation = SamplerOptions & F_WSMP_NO_TRUNCATION;
197     NoSampleCompression = SamplerOptions & F_WSMP_NO_COMPRESSION;
198     SampleLoops = wsmp->ReadUint32();
199     pSampleLoops = (SampleLoops) ? new sample_loop_t[SampleLoops] : NULL;
200     wsmp->SetPos(headersize);
201     for (uint32_t i = 0; i < SampleLoops; i++) {
202 schoenebeck 11 wsmp->Read(pSampleLoops + i, 4, 4);
203 schoenebeck 2 if (pSampleLoops[i].Size > sizeof(sample_loop_t)) { // if loop struct was extended
204     wsmp->SetPos(pSampleLoops[i].Size - sizeof(sample_loop_t), RIFF::stream_curpos);
205     }
206     }
207     }
208    
209     Sampler::~Sampler() {
210     if (pSampleLoops) delete[] pSampleLoops;
211     }
212    
213    
214    
215     // *************** Sample ***************
216     // *
217    
218     Sample::Sample(File* pFile, RIFF::List* waveList, unsigned long WavePoolOffset) : Resource(pFile, waveList) {
219     ulWavePoolOffset = WavePoolOffset - LIST_HEADER_SIZE;
220     pCkFormat = waveList->GetSubChunk(CHUNK_ID_FMT);
221     pCkData = waveList->GetSubChunk(CHUNK_ID_DATA);
222     if (!pCkFormat || !pCkData) throw DLS::Exception("Mandatory chunks in wave list not found.");
223    
224     // common fields
225     FormatTag = pCkFormat->ReadUint16();
226     Channels = pCkFormat->ReadUint16();
227     SamplesPerSecond = pCkFormat->ReadUint32();
228     AverageBytesPerSecond = pCkFormat->ReadUint32();
229     BlockAlign = pCkFormat->ReadUint16();
230    
231     // PCM format specific
232     if (FormatTag == WAVE_FORMAT_PCM) {
233     BitDepth = pCkFormat->ReadUint16();
234     FrameSize = (FormatTag == WAVE_FORMAT_PCM) ? (BitDepth / 8) * Channels
235     : 0;
236     SamplesTotal = (FormatTag == WAVE_FORMAT_PCM) ? pCkData->GetSize() / FrameSize
237     : 0;
238     }
239     else {
240     BitDepth = 0;
241     FrameSize = 0;
242     SamplesTotal = 0;
243     }
244     }
245    
246     void* Sample::LoadSampleData() {
247     return pCkData->LoadChunkData();
248     }
249    
250     void Sample::ReleaseSampleData() {
251     pCkData->ReleaseChunkData();
252     }
253    
254     /**
255     * Sets the position within the sample (in sample points, not in
256     * bytes). Use this method and <i>Read()</i> if you don't want to load
257     * the sample into RAM, thus for disk streaming.
258     *
259     * @param SampleCount number of sample points
260     * @param Whence to which relation \a SampleCount refers to
261     */
262     unsigned long Sample::SetPos(unsigned long SampleCount, RIFF::stream_whence_t Whence) {
263     if (FormatTag != WAVE_FORMAT_PCM) return 0; // failed: wave data not PCM format
264     unsigned long orderedBytes = SampleCount * FrameSize;
265     unsigned long result = pCkData->SetPos(orderedBytes, Whence);
266     return (result == orderedBytes) ? SampleCount
267     : result / FrameSize;
268     }
269    
270     /**
271     * Reads \a SampleCount number of sample points from the current
272     * position into the buffer pointed by \a pBuffer and increments the
273     * position within the sample. Use this method and <i>SetPos()</i> if you
274     * don't want to load the sample into RAM, thus for disk streaming.
275     *
276     * @param pBuffer destination buffer
277     * @param SampleCount number of sample points to read
278     */
279     unsigned long Sample::Read(void* pBuffer, unsigned long SampleCount) {
280     if (FormatTag != WAVE_FORMAT_PCM) return 0; // failed: wave data not PCM format
281 schoenebeck 11 return pCkData->Read(pBuffer, SampleCount, FrameSize); // FIXME: channel inversion due to endian correction?
282 schoenebeck 2 }
283    
284    
285    
286     // *************** Region ***************
287     // *
288    
289     Region::Region(Instrument* pInstrument, RIFF::List* rgnList) : Resource(pInstrument, rgnList), Articulator(rgnList), Sampler(rgnList) {
290     pCkRegion = rgnList;
291    
292     RIFF::Chunk* rgnh = rgnList->GetSubChunk(CHUNK_ID_RGNH);
293 schoenebeck 11 rgnh->Read(&KeyRange, 2, 2);
294     rgnh->Read(&VelocityRange, 2, 2);
295 schoenebeck 2 uint16_t optionflags = rgnh->ReadUint16();
296     SelfNonExclusive = optionflags & F_RGN_OPTION_SELFNONEXCLUSIVE;
297     KeyGroup = rgnh->ReadUint16();
298     // Layer is optional
299     if (rgnh->RemainingBytes() >= sizeof(uint16_t)) {
300     rgnh->Read(&Layer, 1, sizeof(uint16_t));
301     }
302     else Layer = 0;
303    
304     RIFF::Chunk* wlnk = rgnList->GetSubChunk(CHUNK_ID_WLNK);
305     optionflags = wlnk->ReadUint16();
306     PhaseMaster = optionflags & F_WAVELINK_PHASE_MASTER;
307     MultiChannel = optionflags & F_WAVELINK_MULTICHANNEL;
308     PhaseGroup = wlnk->ReadUint16();
309     Channel = wlnk->ReadUint32();
310     WavePoolTableIndex = wlnk->ReadUint32();
311    
312     pSample = NULL;
313     }
314    
315     Region::~Region() {
316     }
317    
318     Sample* Region::GetSample() {
319     if (pSample) return pSample;
320     File* file = (File*) GetParent()->GetParent();
321     unsigned long soughtoffset = file->pWavePoolTable[WavePoolTableIndex];
322     Sample* sample = file->GetFirstSample();
323     while (sample) {
324     if (sample->ulWavePoolOffset == soughtoffset) return (pSample = sample);
325     sample = file->GetNextSample();
326     }
327     return NULL;
328     }
329    
330    
331    
332     // *************** Instrument ***************
333     // *
334    
335     Instrument::Instrument(File* pFile, RIFF::List* insList) : Resource(pFile, insList), Articulator(insList) {
336     pCkInstrument = insList;
337    
338     RIFF::Chunk* insh = pCkInstrument->GetSubChunk(CHUNK_ID_INSH);
339     if (!insh) throw DLS::Exception("Mandatory chunks in <lins> list chunk not found.");
340     Regions = insh->ReadUint32();
341     midi_locale_t locale;
342 schoenebeck 11 insh->Read(&locale, 2, 4);
343 schoenebeck 2 MIDIProgram = locale.instrument;
344     IsDrum = locale.bank & DRUM_TYPE_MASK;
345     MIDIBankCoarse = (uint8_t) MIDI_BANK_COARSE(locale.bank);
346     MIDIBankFine = (uint8_t) MIDI_BANK_FINE(locale.bank);
347     MIDIBank = MIDI_BANK_MERGE(MIDIBankCoarse, MIDIBankFine);
348    
349     pRegions = NULL;
350     }
351    
352     Region* Instrument::GetFirstRegion() {
353     if (!pRegions) LoadRegions();
354     if (!pRegions) return NULL;
355     RegionsIterator = pRegions->begin();
356     return (RegionsIterator != pRegions->end()) ? *RegionsIterator : NULL;
357     }
358    
359     Region* Instrument::GetNextRegion() {
360     if (!pRegions) return NULL;
361     RegionsIterator++;
362     return (RegionsIterator != pRegions->end()) ? *RegionsIterator : NULL;
363     }
364    
365     void Instrument::LoadRegions() {
366     RIFF::List* lrgn = pCkInstrument->GetSubList(LIST_TYPE_LRGN);
367     if (!lrgn) throw DLS::Exception("Mandatory chunks in <ins > chunk not found.");
368     uint32_t regionCkType = (lrgn->GetSubList(LIST_TYPE_RGN2)) ? LIST_TYPE_RGN2 : LIST_TYPE_RGN; // prefer regions level 2
369     RIFF::List* rgn = lrgn->GetFirstSubList();
370     while (rgn) {
371     if (rgn->GetListType() == regionCkType) {
372     if (!pRegions) pRegions = new RegionList;
373     pRegions->push_back(new Region(this, rgn));
374     }
375     rgn = lrgn->GetNextSubList();
376     }
377     }
378    
379     Instrument::~Instrument() {
380     if (pRegions) {
381     RegionList::iterator iter = pRegions->begin();
382     RegionList::iterator end = pRegions->end();
383     while (iter != end) {
384     delete *iter;
385     iter++;
386     }
387     delete pRegions;
388     }
389     }
390    
391    
392    
393     // *************** File ***************
394     // *
395    
396     File::File(RIFF::File* pRIFF) : Resource(NULL, pRIFF) {
397     if (!pRIFF) throw DLS::Exception("NULL pointer reference to RIFF::File object.");
398     this->pRIFF = pRIFF;
399    
400     RIFF::Chunk* ckVersion = pRIFF->GetSubChunk(CHUNK_ID_VERS);
401     if (ckVersion) {
402     pVersion = new version_t;
403 schoenebeck 11 ckVersion->Read(pVersion, 4, 2);
404 schoenebeck 2 }
405     else pVersion = NULL;
406    
407     RIFF::Chunk* colh = pRIFF->GetSubChunk(CHUNK_ID_COLH);
408     if (!colh) throw DLS::Exception("Mandatory chunks in RIFF list chunk not found.");
409     Instruments = colh->ReadUint32();
410    
411     RIFF::Chunk* ptbl = pRIFF->GetSubChunk(CHUNK_ID_PTBL);
412     if (!ptbl) throw DLS::Exception("Mandatory <ptbl> chunk not found.");
413     uint32_t headersize = ptbl->ReadUint32();
414     WavePoolCount = ptbl->ReadUint32();
415     pWavePoolTable = new uint32_t[WavePoolCount];
416     ptbl->SetPos(headersize);
417    
418 schoenebeck 317 // Check for 64 bit offsets (used in gig v3 files)
419     if (ptbl->GetSize() - headersize == WavePoolCount * 8) {
420     for (int i = 0 ; i < WavePoolCount ; i++) {
421     // Just ignore the upper bits for now
422     uint32_t upper = ptbl->ReadUint32();
423     pWavePoolTable[i] = ptbl->ReadUint32();
424     if (upper || (pWavePoolTable[i] & 0x80000000))
425     throw DLS::Exception("Files larger than 2 GB not yet supported");
426     }
427     }
428     else ptbl->Read(pWavePoolTable, WavePoolCount, sizeof(uint32_t));
429    
430 schoenebeck 2 pSamples = NULL;
431     pInstruments = NULL;
432     Instruments = 0;
433     }
434    
435     File::~File() {
436     if (pInstruments) {
437     InstrumentList::iterator iter = pInstruments->begin();
438     InstrumentList::iterator end = pInstruments->end();
439     while (iter != end) {
440     delete *iter;
441     iter++;
442     }
443     delete pInstruments;
444     }
445    
446     if (pSamples) {
447     SampleList::iterator iter = pSamples->begin();
448     SampleList::iterator end = pSamples->end();
449     while (iter != end) {
450     delete *iter;
451     iter++;
452     }
453     delete pSamples;
454     }
455    
456     if (pWavePoolTable) delete[] pWavePoolTable;
457     if (pVersion) delete pVersion;
458     }
459    
460     Sample* File::GetFirstSample() {
461     if (!pSamples) LoadSamples();
462     if (!pSamples) return NULL;
463     SamplesIterator = pSamples->begin();
464     return (SamplesIterator != pSamples->end()) ? *SamplesIterator : NULL;
465     }
466    
467     Sample* File::GetNextSample() {
468     if (!pSamples) return NULL;
469     SamplesIterator++;
470     return (SamplesIterator != pSamples->end()) ? *SamplesIterator : NULL;
471     }
472    
473     void File::LoadSamples() {
474     RIFF::List* wvpl = pRIFF->GetSubList(LIST_TYPE_WVPL);
475     if (wvpl) {
476     unsigned long wvplFileOffset = wvpl->GetFilePos();
477     RIFF::List* wave = wvpl->GetFirstSubList();
478     while (wave) {
479     if (wave->GetListType() == LIST_TYPE_WAVE) {
480     if (!pSamples) pSamples = new SampleList;
481     unsigned long waveFileOffset = wave->GetFilePos();
482     pSamples->push_back(new Sample(this, wave, waveFileOffset - wvplFileOffset));
483     }
484     wave = wvpl->GetNextSubList();
485     }
486     }
487     else { // Seen a dwpl list chunk instead of a wvpl list chunk in some file (officially not DLS compliant)
488     RIFF::List* dwpl = pRIFF->GetSubList(LIST_TYPE_DWPL);
489     if (dwpl) {
490     unsigned long dwplFileOffset = dwpl->GetFilePos();
491     RIFF::List* wave = dwpl->GetFirstSubList();
492     while (wave) {
493     if (wave->GetListType() == LIST_TYPE_WAVE) {
494     if (!pSamples) pSamples = new SampleList;
495     unsigned long waveFileOffset = wave->GetFilePos();
496     pSamples->push_back(new Sample(this, wave, waveFileOffset - dwplFileOffset));
497     }
498     wave = dwpl->GetNextSubList();
499     }
500     }
501     }
502     }
503    
504     Instrument* File::GetFirstInstrument() {
505     if (!pInstruments) LoadInstruments();
506     if (!pInstruments) return NULL;
507     InstrumentsIterator = pInstruments->begin();
508     return (InstrumentsIterator != pInstruments->end()) ? *InstrumentsIterator : NULL;
509     }
510    
511     Instrument* File::GetNextInstrument() {
512     if (!pInstruments) return NULL;
513     InstrumentsIterator++;
514     return (InstrumentsIterator != pInstruments->end()) ? *InstrumentsIterator : NULL;
515     }
516    
517     void File::LoadInstruments() {
518     RIFF::List* lstInstruments = pRIFF->GetSubList(LIST_TYPE_LINS);
519     if (lstInstruments) {
520     RIFF::List* lstInstr = lstInstruments->GetFirstSubList();
521     while (lstInstr) {
522     if (lstInstr->GetListType() == LIST_TYPE_INS) {
523     if (!pInstruments) pInstruments = new InstrumentList;
524     pInstruments->push_back(new Instrument(this, lstInstr));
525     }
526     lstInstr = lstInstruments->GetNextSubList();
527     }
528     }
529     }
530    
531    
532    
533     // *************** Exception ***************
534     // *
535    
536     Exception::Exception(String Message) : RIFF::Exception(Message) {
537     }
538    
539     void Exception::PrintMessage() {
540     std::cout << "DLS::Exception: " << Message << std::endl;
541     }
542    
543     } // namespace DLS

  ViewVC Help
Powered by ViewVC