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

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

Parent Directory Parent Directory | Revision Log Revision Log


Revision 11 - (hide annotations) (download)
Sun Nov 16 17:47:00 2003 UTC (20 years, 4 months ago) by schoenebeck
File size: 20430 byte(s)
* src/gig.cpp: fixed bug in decompression algorithm which caused it not to
  detect the end of a stream
* various endian corrections (successfully tested now on ppc)
* minor adjustments to avoid compile errors on some systems
  (using now pow() instead of powl() and --pedantic g++ compiler switch)
* src/RIFF.cpp, src/RIFF.h: added additional API documentation

1 schoenebeck 2 /***************************************************************************
2     * *
3     * libgig - C++ cross-platform Gigasampler format file loader library *
4     * *
5     * Copyright (C) 2003 by Christian Schoenebeck *
6     * <cuse@users.sourceforge.net> *
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 "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     ptbl->Read(pWavePoolTable, WavePoolCount, sizeof(uint32_t));
418    
419     pSamples = NULL;
420     pInstruments = NULL;
421     Instruments = 0;
422     }
423    
424     File::~File() {
425     if (pInstruments) {
426     InstrumentList::iterator iter = pInstruments->begin();
427     InstrumentList::iterator end = pInstruments->end();
428     while (iter != end) {
429     delete *iter;
430     iter++;
431     }
432     delete pInstruments;
433     }
434    
435     if (pSamples) {
436     SampleList::iterator iter = pSamples->begin();
437     SampleList::iterator end = pSamples->end();
438     while (iter != end) {
439     delete *iter;
440     iter++;
441     }
442     delete pSamples;
443     }
444    
445     if (pWavePoolTable) delete[] pWavePoolTable;
446     if (pVersion) delete pVersion;
447     }
448    
449     Sample* File::GetFirstSample() {
450     if (!pSamples) LoadSamples();
451     if (!pSamples) return NULL;
452     SamplesIterator = pSamples->begin();
453     return (SamplesIterator != pSamples->end()) ? *SamplesIterator : NULL;
454     }
455    
456     Sample* File::GetNextSample() {
457     if (!pSamples) return NULL;
458     SamplesIterator++;
459     return (SamplesIterator != pSamples->end()) ? *SamplesIterator : NULL;
460     }
461    
462     void File::LoadSamples() {
463     RIFF::List* wvpl = pRIFF->GetSubList(LIST_TYPE_WVPL);
464     if (wvpl) {
465     unsigned long wvplFileOffset = wvpl->GetFilePos();
466     RIFF::List* wave = wvpl->GetFirstSubList();
467     while (wave) {
468     if (wave->GetListType() == LIST_TYPE_WAVE) {
469     if (!pSamples) pSamples = new SampleList;
470     unsigned long waveFileOffset = wave->GetFilePos();
471     pSamples->push_back(new Sample(this, wave, waveFileOffset - wvplFileOffset));
472     }
473     wave = wvpl->GetNextSubList();
474     }
475     }
476     else { // Seen a dwpl list chunk instead of a wvpl list chunk in some file (officially not DLS compliant)
477     RIFF::List* dwpl = pRIFF->GetSubList(LIST_TYPE_DWPL);
478     if (dwpl) {
479     unsigned long dwplFileOffset = dwpl->GetFilePos();
480     RIFF::List* wave = dwpl->GetFirstSubList();
481     while (wave) {
482     if (wave->GetListType() == LIST_TYPE_WAVE) {
483     if (!pSamples) pSamples = new SampleList;
484     unsigned long waveFileOffset = wave->GetFilePos();
485     pSamples->push_back(new Sample(this, wave, waveFileOffset - dwplFileOffset));
486     }
487     wave = dwpl->GetNextSubList();
488     }
489     }
490     }
491     }
492    
493     Instrument* File::GetFirstInstrument() {
494     if (!pInstruments) LoadInstruments();
495     if (!pInstruments) return NULL;
496     InstrumentsIterator = pInstruments->begin();
497     return (InstrumentsIterator != pInstruments->end()) ? *InstrumentsIterator : NULL;
498     }
499    
500     Instrument* File::GetNextInstrument() {
501     if (!pInstruments) return NULL;
502     InstrumentsIterator++;
503     return (InstrumentsIterator != pInstruments->end()) ? *InstrumentsIterator : NULL;
504     }
505    
506     void File::LoadInstruments() {
507     RIFF::List* lstInstruments = pRIFF->GetSubList(LIST_TYPE_LINS);
508     if (lstInstruments) {
509     RIFF::List* lstInstr = lstInstruments->GetFirstSubList();
510     while (lstInstr) {
511     if (lstInstr->GetListType() == LIST_TYPE_INS) {
512     if (!pInstruments) pInstruments = new InstrumentList;
513     pInstruments->push_back(new Instrument(this, lstInstr));
514     }
515     lstInstr = lstInstruments->GetNextSubList();
516     }
517     }
518     }
519    
520    
521    
522     // *************** Exception ***************
523     // *
524    
525     Exception::Exception(String Message) : RIFF::Exception(Message) {
526     }
527    
528     void Exception::PrintMessage() {
529     std::cout << "DLS::Exception: " << Message << std::endl;
530     }
531    
532     } // namespace DLS

  ViewVC Help
Powered by ViewVC