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

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

Parent Directory Parent Directory | Revision Log Revision Log


Revision 2 - (hide annotations) (download)
Sat Oct 25 20:15:04 2003 UTC (20 years, 5 months ago) by schoenebeck
File size: 20121 byte(s)
Initial revision

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

  ViewVC Help
Powered by ViewVC