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

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

Parent Directory Parent Directory | Revision Log Revision Log


Revision 2572 - (hide annotations) (download)
Thu May 22 12:14:04 2014 UTC (9 years, 11 months ago) by schoenebeck
File size: 47169 byte(s)
* Added fork of libakai (this fork provides Linux support) which
  allows reading AKAI medias. Comes with two command line tools
  'akaidump' and 'akaiextract'. Also added a man page for each
  tool.

1 schoenebeck 2572 /*
2     libakai - C++ cross-platform akai sample disk reader
3     Copyright (C) 2002-2003 Sébastien Métrot
4    
5     Linux port by Christian Schoenebeck <cuse@users.sourceforge.net> 2003-2014
6    
7     This library is free software; you can redistribute it and/or
8     modify it under the terms of the GNU Lesser General Public
9     License as published by the Free Software Foundation; either
10     version 2.1 of the License, or (at your option) any later version.
11    
12     This library is distributed in the hope that it will be useful,
13     but WITHOUT ANY WARRANTY; without even the implied warranty of
14     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15     Lesser General Public License for more details.
16    
17     You should have received a copy of the GNU Lesser General Public
18     License along with this library; if not, write to the Free Software
19     Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
20     */
21     // Akai.cpp
22    
23     #include "Akai.h"
24    
25     #include <stdio.h>
26     #include <string.h>
27     #include <unistd.h>
28     #include <fcntl.h>
29     #include <sys/ioctl.h>
30     #include <sys/types.h>
31     #include <sys/stat.h>
32     #include <errno.h>
33     #include <paths.h>
34     #ifdef _CARBON_
35     #include <sys/param.h>
36     #include <IOKit/IOKitLib.h>
37     #include <IOKit/IOBSD.h>
38     #include <IOKit/storage/IOMediaBSDClient.h>
39     #include <IOKit/storage/IOMedia.h>
40     #include <IOKit/storage/IOCDMedia.h>
41     #include <IOKit/storage/IOCDTypes.h>
42     #include <CoreFoundation/CoreFoundation.h>
43     #endif
44    
45     //////////////////////////////////
46     // AkaiSample:
47     AkaiSample::AkaiSample(DiskImage* pDisk, AkaiVolume* pParent, const AkaiDirEntry& DirEntry)
48     : AkaiDiskElement(pDisk->GetPos())
49     {
50     mpParent = pParent;
51     mpDisk = pDisk;
52     mDirEntry = DirEntry;
53     mpSamples = NULL;
54     mHeaderOK = false;
55     mPos = 0;
56    
57     //
58     LoadHeader();
59     }
60    
61     AkaiSample::~AkaiSample()
62     {
63     if (mpSamples)
64     free(mpSamples);
65     }
66    
67     AkaiDirEntry AkaiSample::GetDirEntry()
68     {
69     return mDirEntry;
70     }
71    
72     bool AkaiSample::LoadSampleData()
73     {
74     if (!LoadHeader())
75     return false;
76     if (mpSamples)
77     return true;
78    
79     mpDisk->SetPos(mImageOffset);
80     mpSamples = (int16_t*) malloc(mNumberOfSamples * sizeof(int16_t));
81     if (!mpSamples)
82     return false;
83    
84     mpDisk->ReadInt16((uint16_t*)mpSamples, mNumberOfSamples);
85     return true;
86     }
87    
88     void AkaiSample::ReleaseSampleData()
89     {
90     if (!mpSamples)
91     return;
92     free(mpSamples);
93     mpSamples = NULL;
94     }
95    
96     int AkaiSample::SetPos(int Where, akai_stream_whence_t Whence)
97     {
98     if (!mHeaderOK) return -1;
99     int w = Where;
100     switch (Whence)
101     {
102     case akai_stream_start:
103     mPos = w;
104     break;
105     /*case eStreamRewind:
106     w = -w;*/
107     case akai_stream_curpos:
108     mPos += w;
109     break;
110     case akai_stream_end:
111     mPos = mNumberOfSamples - w;
112     break;
113     }
114     if (mPos > mNumberOfSamples) mPos = mNumberOfSamples;
115     if (mPos < 0) mPos = 0;
116     return mPos;
117     }
118    
119     int AkaiSample::Read(void* pBuffer, uint SampleCount)
120     {
121     if (!mHeaderOK) return 0;
122    
123     if (mPos + SampleCount > mNumberOfSamples) SampleCount = mNumberOfSamples - mPos;
124    
125     mpDisk->SetPos(mImageOffset + mPos * 2); // FIXME: assumes 16 bit sample depth
126     mpDisk->ReadInt16((uint16_t*)pBuffer, SampleCount);
127     return SampleCount;
128     }
129    
130     bool AkaiSample::LoadHeader()
131     {
132     if (mHeaderOK)
133     return true;
134    
135     mpDisk->SetPos(mpParent->GetParent()->GetOffset() + mDirEntry.mStart * AKAI_BLOCK_SIZE );
136    
137     // Length Format Description
138     // --------------------------------------------------------------
139     // 1 3
140     if (mpDisk->ReadInt8() != AKAI_SAMPLE_ID)
141     return false;
142     // 1 Not important: 0 for 22050Hz, 1 for 44100Hz
143     mpDisk->ReadInt8();
144     // 1 unsigned MIDI root note (C3=60)
145     mMidiRootNote = mpDisk->ReadInt8();
146     // 12 AKAII Filename
147     char buffer[13];
148     mpDisk->Read(buffer, 12, 1);
149     AkaiToAscii(buffer, 12);
150     mName = buffer;
151    
152     // 1 128
153     mpDisk->ReadInt8();
154     // 1 unsigned Number of active loops
155     mActiveLoops = mpDisk->ReadInt8();
156     // 1 unsigned char First active loop (0 for none)
157     mFirstActiveLoop = mpDisk->ReadInt8();
158     // 1 0
159     mpDisk->ReadInt8();
160     // 1 unsigned Loop mode: 0=in release 1=until release
161     // 2=none 3=play to end
162     mLoopMode = mpDisk->ReadInt8();
163     // 1 signed Cents tune -50...+50
164     mTuneCents = mpDisk->ReadInt8();
165     // 1 signed Semi tune -50...+50
166     mTuneSemitones = mpDisk->ReadInt8();
167     // 4 0,8,2,0
168     mpDisk->ReadInt8();
169     mpDisk->ReadInt8();
170     mpDisk->ReadInt8();
171     mpDisk->ReadInt8();
172     //
173     // 4 unsigned Number of sample words
174     mNumberOfSamples = mpDisk->ReadInt32();
175     // 4 unsigned Start marker
176     mStartMarker = mpDisk->ReadInt32();
177     // 4 unsigned End marker
178     mEndMarker = mpDisk->ReadInt32();
179     //
180     // 4 unsigned Loop 1 marker
181     // 2 unsigned Loop 1 fine length (65536ths)
182     // 4 unsigned Loop 1 coarse length (words)
183     // 2 unsigned Loop 1 time (msec. or 9999=infinite)
184     //
185     // 84 [as above] Loops 2 to 8
186     //
187     int i;
188     for (i=0; i<8; i++)
189     mLoops[i].Load(mpDisk);
190     // 4 0,0,255,255
191     mpDisk->ReadInt32();
192     // 2 unsigned Sampling frequency
193     mSamplingFrequency = mpDisk->ReadInt16();
194     // 1 signed char Loop tune offset -50...+50
195     mLoopTuneOffset = mpDisk->ReadInt8();
196    
197     mImageOffset = mpParent->GetParent()->GetOffset() + mDirEntry.mStart * AKAI_BLOCK_SIZE + 150; // 150 is the size of the header
198    
199     //FIXME: no header validation yet implemented
200     return (mHeaderOK = true);
201     }
202    
203     bool AkaiSampleLoop::Load(DiskImage* pDisk)
204     {
205     // 4 unsigned Loop 1 marker
206     mMarker = pDisk->ReadInt32();
207     // 2 unsigned Loop 1 fine length (65536ths)
208     mFineLength = pDisk->ReadInt16();
209     // 4 unsigned Loop 1 coarse length (words)
210     mCoarseLength = pDisk->ReadInt32();
211     // 2 unsigned Loop 1 time (msec. or 9999=infinite)
212     mTime = pDisk->ReadInt16();
213     return true;
214     }
215    
216     //////////////////////////////////
217     // AkaiProgram:
218     AkaiProgram::AkaiProgram(DiskImage* pDisk, AkaiVolume* pParent, const AkaiDirEntry& DirEntry)
219     : AkaiDiskElement(pDisk->GetPos())
220     {
221     mpParent = pParent;
222     mpDisk = pDisk;
223     mDirEntry = DirEntry;
224     mpKeygroups = NULL;
225     Load();
226     }
227    
228     AkaiProgram::~AkaiProgram()
229     {
230     if (mpKeygroups)
231     delete[] mpKeygroups;
232     }
233    
234     AkaiDirEntry AkaiProgram::GetDirEntry()
235     {
236     return mDirEntry;
237     }
238    
239     bool AkaiProgram::Load()
240     {
241     // Read each of the program parameters
242     uint temppos = mpDisk->GetPos();
243     mpDisk->SetPos(mpParent->GetParent()->GetOffset() + mDirEntry.mStart * AKAI_BLOCK_SIZE );
244     // byte description default range/comments
245     // ---------------------------------------------------------------------------
246     // 1 program ID 1
247     uint8_t ProgID = mpDisk->ReadInt8();
248     if (ProgID != AKAI_PROGRAM_ID)
249     {
250     mpDisk->SetPos(temppos);
251     return false;
252     }
253     // 2-3 first keygroup address 150,0
254     uint16_t KeygroupAddress = mpDisk->ReadInt16();
255     // 4-15 program name 10,10,10... AKAII character set
256     char buffer[13];
257     mpDisk->Read(buffer, 12, 1);
258     AkaiToAscii(buffer, 12);
259     mName = buffer;
260     // 16 MIDI program number 0 0..127
261     mMidiProgramNumber = mpDisk->ReadInt8();
262     // 17 MIDI channel 0 0..15, 255=OMNI
263     mMidiChannel = mpDisk->ReadInt8();
264     // 18 polyphony 15 1..16
265     mPolyphony = mpDisk->ReadInt8();
266     // 19 priority 1 0=LOW 1=NORM 2=HIGH 3=HOLD
267     mPriority = mpDisk->ReadInt8();
268     // 20 low key 24 24..127
269     mLowKey = mpDisk->ReadInt8();
270     // 21 high key 127 24..127
271     mHighKey = mpDisk->ReadInt8();
272     // 22 octave shift 0 -2..2
273     mOctaveShift = mpDisk->ReadInt8();
274     // 23 aux output select 255 0..7, 255=OFF
275     mAuxOutputSelect = mpDisk->ReadInt8();
276     // 24 mix output level 99 0..99
277     mMixOutputSelect = mpDisk->ReadInt8();
278     // 25 mix output pan 0 -50..50
279     mMixPan = mpDisk->ReadInt8();
280     // 26 volume 80 0..99
281     mVolume = mpDisk->ReadInt8();
282     // 27 vel>volume 20 -50..50
283     mVelocityToVolume = mpDisk->ReadInt8();
284     // 28 key>volume 0 -50..50
285     mKeyToVolume = mpDisk->ReadInt8();
286     // 29 pres>volume 0 -50..50
287     mPressureToVolume = mpDisk->ReadInt8();
288     // 30 pan lfo rate 50 0..99
289     mPanLFORate = mpDisk->ReadInt8();
290     // 31 pan lfo depth 0 0..99
291     mPanLFODepth = mpDisk->ReadInt8();
292     // 32 pan lfo delay 0 0..99
293     mPanLFODelay = mpDisk->ReadInt8();
294     // 33 key>pan 0 -50..50
295     mKeyToPan = mpDisk->ReadInt8();
296     // 34 lfo rate 50 0..99
297     mLFORate = mpDisk->ReadInt8();
298     // 35 lfo depth 0 0..99
299     mLFODepth = mpDisk->ReadInt8();
300     // 36 lfo delay 0 0..99
301     mLFODelay = mpDisk->ReadInt8();
302     // 37 mod>lfo depth 30 0..99
303     mModulationToLFODepth = mpDisk->ReadInt8();
304     // 38 pres>lfo depth 0 0..99
305     mPressureToLFODepth = mpDisk->ReadInt8();
306     // 39 vel>lfo depth 0 0..99
307     mVelocityToLFODepth = mpDisk->ReadInt8();
308     // 40 bend>pitch 2 0..12 semitones
309     mBendToPitch = mpDisk->ReadInt8();
310     // 41 pres>pitch 0 -12..12 semitones
311     mPressureToPitch = mpDisk->ReadInt8();
312     // 42 keygroup crossfade 0 0=OFF 1=ON
313     mKeygroupCrossfade = mpDisk->ReadInt8()?true:false;
314     // 43 number of keygroups 1 1..99
315     mNumberOfKeygroups = mpDisk->ReadInt8();
316     // 44 (internal use) 0 program number
317     mpDisk->ReadInt8();
318     // 45-56 key temperament C,C#,D... 0 -25..25 cents
319     uint i;
320     for (i = 0; i<11; i++)
321     mKeyTemperament[i] = mpDisk->ReadInt8();
322     // 57 fx output 0 0=OFF 1=ON
323     mFXOutput = mpDisk->ReadInt8()?true:false;
324     // 58 mod>pan 0 -50..50
325     mModulationToPan = mpDisk->ReadInt8();
326     // 59 stereo coherence 0 0=OFF 1=ON
327     mStereoCoherence = mpDisk->ReadInt8()?true:false;
328     // 60 lfo desync 1 0=OFF 1=ON
329     mLFODesync = mpDisk->ReadInt8()?true:false;
330     // 61 pitch law 0 0=LINEAR
331     mPitchLaw = mpDisk->ReadInt8();
332     // 62 voice re-assign 0 0=OLDEST 1=QUIETEST
333     mVoiceReassign = mpDisk->ReadInt8();
334     // 63 softped>volume 10 0..99
335     mSoftpedToVolume = mpDisk->ReadInt8();
336     // 64 softped>attack 10 0..99
337     mSoftpedToAttack = mpDisk->ReadInt8();
338     // 65 softped>filt 10 0..99
339     mSoftpedToFilter = mpDisk->ReadInt8();
340     // 66 tune cents 0 -128..127 (-50..50 cents)
341     mSoftpedToTuneCents = mpDisk->ReadInt8();
342     // 67 tune semitones 0 -50..50
343     mSoftpedToTuneSemitones = mpDisk->ReadInt8();
344     // 68 key>lfo rate 0 -50..50
345     mKeyToLFORate = mpDisk->ReadInt8();
346     // 69 key>lfo depth 0 -50..50
347     mKeyToLFODepth = mpDisk->ReadInt8();
348     // 70 key>lfo delay 0 -50..50
349     mKeyToLFODelay = mpDisk->ReadInt8();
350     // 71 voice output scale 1 0=-6dB 1=0dB 2=+12dB
351     mVoiceOutputScale = mpDisk->ReadInt8();
352     // 72 stereo output scale 0 0=0dB 1=+6dB
353     mStereoOutputScale = mpDisk->ReadInt8();
354     // 73-150 (not used)
355    
356     // Read the key groups:
357     if (mpKeygroups)
358     delete[] mpKeygroups;
359     mpKeygroups = new AkaiKeygroup[mNumberOfKeygroups];
360     for (i = 0; i < mNumberOfKeygroups; i++)
361     {
362     // Go where the key group is on the disk:
363     mpDisk->SetPos(mpParent->GetParent()->GetOffset() + mDirEntry.mStart * AKAI_BLOCK_SIZE + 150 * (i+1));
364     if (!mpKeygroups[i].Load(mpDisk))
365     {
366     mpDisk->SetPos(temppos);
367     return false;
368     }
369     }
370    
371     mpDisk->SetPos(temppos);
372     return true;
373     }
374    
375     uint AkaiProgram::ListSamples(std::list<String>& rSamples)
376     {
377     return 0;
378     }
379    
380     AkaiSample* AkaiProgram::GetSample(uint Index)
381     {
382     return NULL;
383     }
384    
385     AkaiSample* AkaiProgram::GetSample(const String& rName)
386     {
387     return NULL;
388     }
389    
390     // AkaiKeygroup:
391     bool AkaiKeygroup::Load(DiskImage* pDisk)
392     {
393     uint i;
394     // byte description default range/comments
395     // ---------------------------------------------------------------------------
396     // 1 keygroup ID 2
397     if (pDisk->ReadInt8() != AKAI_KEYGROUP_ID)
398     return false;
399     // 2-3 next keygroup address 44,1 300,450,600,750.. (16-bit)
400     uint16_t NextKeygroupAddress = pDisk->ReadInt16();
401     // 4 low key 24 24..127
402     mLowKey = pDisk->ReadInt8();
403     // 5 high key 127 24..127
404     mHighKey = pDisk->ReadInt8();
405     // 6 tune cents 0 -128..127 (-50..50 cents)
406     mTuneCents = pDisk->ReadInt8();
407     // 7 tune semitones 0 -50..50
408     mTuneSemitones = pDisk->ReadInt8();
409     // 8 filter 99 0..99
410     mFilter = pDisk->ReadInt8();
411     // 9 key>filter 12 0..24 semitone/oct
412     mKeyToFilter = pDisk->ReadInt8();
413     // 10 vel>filt 0 -50..50
414     mVelocityToFilter = pDisk->ReadInt8();
415     // 11 pres>filt 0 -50..50
416     mPressureToFilter = pDisk->ReadInt8();
417     // 12 env2>filt 0 -50..50
418     mEnveloppe2ToFilter = pDisk->ReadInt8();
419    
420     // 13 env1 attack 0 0..99
421     // 14 env1 decay 30 0..99
422     // 15 env1 sustain 99 0..99
423     // 16 env1 release 45 0..99
424     // 17 env1 vel>attack 0 -50..50
425     // 18 env1 vel>release 0 -50..50
426     // 19 env1 offvel>release 0 -50..50
427     // 20 env1 key>dec&rel 0 -50..50
428     // 21 env2 attack 0 0..99
429     // 22 env2 decay 50 0..99
430     // 23 env2 sustain 99 0..99
431     // 24 env2 release 45 0..99
432     // 25 env2 vel>attack 0 -50..50
433     // 26 env2 vel>release 0 -50..50
434     // 27 env2 offvel>release 0 -50..50
435     // 28 env2 key>dec&rel 0 -50..50
436     for (i=0; i<2; i++)
437     mEnveloppes[i].Load(pDisk);
438    
439     // 29 vel>env2>filter 0 -50..50
440     mVelocityToEnveloppe2ToFilter = pDisk->ReadInt8();
441     // 30 env2>pitch 0 -50..50
442     mEnveloppe2ToPitch = pDisk->ReadInt8();
443     // 31 vel zone crossfade 1 0=OFF 1=ON
444     mVelocityZoneCrossfade = pDisk->ReadInt8()?true:false;
445     // 32 vel zones used 4
446     mVelocityZoneUsed = pDisk->ReadInt8();
447     // 33 (internal use) 255
448     pDisk->ReadInt8();
449     // 34 (internal use) 255
450     pDisk->ReadInt8();
451     //
452    
453     // 35-46 sample 1 name 10,10,10... AKAII character set
454     // 47 low vel 0 0..127
455     // 48 high vel 127 0..127
456     // 49 tune cents 0 -128..127 (-50..50 cents)
457     // 50 tune semitones 0 -50..50
458     // 51 loudness 0 -50..+50
459     // 52 filter 0 -50..+50
460     // 53 pan 0 -50..+50
461     // 54 loop mode 0 0=AS_SAMPLE 1=LOOP_IN_REL
462     // 2=LOOP_UNTIL_REL 3=NO_LOOP
463     // 4=PLAY_TO_END
464     // 55 (internal use) 255
465     // 56 (internal use) 255
466     // 57-58 (internal use) 44,1
467     //
468     // 59-82 [repeat 35-58 for sample 2]
469     //
470     // 83-106 [repeat 35-58 for sample 3]
471     //
472     // 107-130 [repeat 35-58 for sample 4]
473     //
474     for (i=0; i<4; i++)
475     mSamples[i].Load(pDisk);
476    
477     // 131 beat detune 0 -50..50
478     mBeatDetune = pDisk->ReadInt8();
479     // 132 hold attack until loop 0 0=OFF 1=ON
480     mHoldAttackUntilLoop = pDisk->ReadInt8()?true:false;
481     // 133-136 sample 1-4 key tracking 0 0=TRACK 1=FIXED
482     for (i=0; i<4; i++)
483     mSampleKeyTracking[i] = pDisk->ReadInt8()?true:false;
484     // 137-140 sample 1-4 aux out offset 0 0..7
485     for (i=0; i<4; i++)
486     mSampleAuxOutOffset[i] = pDisk->ReadInt8();
487     // 141-148 vel>sample start 0 -9999..9999 (16-bit signed)
488     for (i=0; i<4; i++)
489     mVelocityToSampleStart[i] = pDisk->ReadInt8();
490     // 149 vel>volume offset 0 -50..50
491     for (i=0; i<4; i++)
492     mVelocityToVolumeOffset[i] = pDisk->ReadInt8();
493     // 150 (not used)
494    
495     return true;
496     }
497    
498     bool AkaiEnveloppe::Load(DiskImage* pDisk)
499     {
500     // 13 env1 attack 0 0..99
501     mAttack = pDisk->ReadInt8();
502     // 14 env1 decay 30 0..99
503     mDecay = pDisk->ReadInt8();
504     // 15 env1 sustain 99 0..99
505     mSustain = pDisk->ReadInt8();
506     // 16 env1 release 45 0..99
507     mRelease = pDisk->ReadInt8();
508     // 17 env1 vel>attack 0 -50..50
509     mVelocityToAttack = pDisk->ReadInt8();
510     // 18 env1 vel>release 0 -50..50
511     mVelocityToRelease = pDisk->ReadInt8();
512     // 19 env1 offvel>release 0 -50..50
513     mOffVelocityToRelease = pDisk->ReadInt8();
514     // 20 env1 key>dec&rel 0 -50..50
515     mKeyToDecayAndRelease = pDisk->ReadInt8();
516     return true;
517     }
518    
519     bool AkaiKeygroupSample::Load(DiskImage* pDisk)
520     {
521     // 35-46 sample 1 name 10,10,10... AKAII character set
522     char buffer[13];
523     pDisk->Read(buffer, 12, 1);
524     AkaiToAscii(buffer, 12);
525     mName = buffer;
526    
527     // 47 low vel 0 0..127
528     mLowLevel = pDisk->ReadInt8();
529     // 48 high vel 127 0..127
530     uint8_t mHighLevel = pDisk->ReadInt8();
531     // 49 tune cents 0 -128..127 (-50..50 cents)
532     int8_t mTuneCents = pDisk->ReadInt8();
533     // 50 tune semitones 0 -50..50
534     int8_t mTuneSemitones = pDisk->ReadInt8();
535     // 51 loudness 0 -50..+50
536     int8_t mLoudness = pDisk->ReadInt8();
537     // 52 filter 0 -50..+50
538     int8_t mFilter = pDisk->ReadInt8();
539     // 53 pan 0 -50..+50
540     int8_t mPan = pDisk->ReadInt8();
541     // 54 loop mode 0 0=AS_SAMPLE 1=LOOP_IN_REL
542     // 2=LOOP_UNTIL_REL 3=NO_LOOP
543     // 4=PLAY_TO_END
544     uint8_t mLoopMode = pDisk->ReadInt8();
545     // 55 (internal use) 255
546     pDisk->ReadInt8();
547     // 56 (internal use) 255
548     pDisk->ReadInt8();
549     // 57-58 (internal use) 44,1
550     pDisk->ReadInt16();
551     //
552    
553     return true;
554     }
555    
556     //////////////////////////////////
557     // AkaiVolume:
558     AkaiVolume::AkaiVolume(DiskImage* pDisk, AkaiPartition* pParent, const AkaiDirEntry& DirEntry)
559     : AkaiDiskElement()
560     {
561     mpDisk = pDisk;
562     mpParent = pParent;
563     mDirEntry = DirEntry;
564    
565     if (mDirEntry.mType != AKAI_TYPE_DIR_S1000 && mDirEntry.mType != AKAI_TYPE_DIR_S3000)
566     {
567     printf("Creating Unknown Volume type! %d\n",mDirEntry.mType);
568     #ifdef _WIN32_
569     OutputDebugString("Creating Unknown Volume type!\n");
570     #endif
571     }
572     }
573    
574     AkaiVolume::~AkaiVolume()
575     {
576     {
577     std::list<AkaiProgram*>::iterator it;
578     std::list<AkaiProgram*>::iterator end = mpPrograms.end();
579     for (it = mpPrograms.begin(); it != end; it++)
580     if (*it)
581     (*it)->Release();
582     }
583    
584     {
585     std::list<AkaiSample*>::iterator it;
586     std::list<AkaiSample*>::iterator end = mpSamples.end();
587     for (it = mpSamples.begin(); it != end; it++)
588     if (*it)
589     (*it)->Release();
590     }
591     }
592    
593     uint AkaiVolume::ReadDir()
594     {
595     uint i;
596     if (mpPrograms.empty())
597     {
598     uint maxfiles = ReadFAT(mpDisk, mpParent,mDirEntry.mStart) ? AKAI_MAX_FILE_ENTRIES_S1000 : AKAI_MAX_FILE_ENTRIES_S3000;
599     for (i = 0; i < maxfiles; i++)
600     {
601     AkaiDirEntry DirEntry;
602     ReadDirEntry(mpDisk, mpParent, DirEntry, mDirEntry.mStart, i);
603     DirEntry.mIndex = i;
604     if (DirEntry.mType == 'p')
605     {
606     AkaiProgram* pProgram = new AkaiProgram(mpDisk, this, DirEntry);
607     pProgram->Acquire();
608     mpPrograms.push_back(pProgram);
609     }
610     else if (DirEntry.mType == 's')
611     {
612     AkaiSample* pSample = new AkaiSample(mpDisk, this, DirEntry);
613     pSample->Acquire();
614     mpSamples.push_back(pSample);
615     }
616     }
617     }
618     return (uint)(mpPrograms.size() + mpSamples.size());
619     }
620    
621     uint AkaiVolume::ListPrograms(std::list<AkaiDirEntry>& rPrograms)
622     {
623     rPrograms.clear();
624     ReadDir();
625    
626     std::list<AkaiProgram*>::iterator it;
627     std::list<AkaiProgram*>::iterator end = mpPrograms.end();
628     for (it = mpPrograms.begin(); it != end; it++)
629     if (*it)
630     rPrograms.push_back((*it)->GetDirEntry());
631     return (uint)rPrograms.size();
632     }
633    
634     AkaiProgram* AkaiVolume::GetProgram(uint Index)
635     {
636     uint i = 0;
637    
638     if (mpPrograms.empty())
639     {
640     std::list<AkaiDirEntry> dummy;
641     ListPrograms(dummy);
642     }
643    
644     std::list<AkaiProgram*>::iterator it;
645     std::list<AkaiProgram*>::iterator end = mpPrograms.end();
646     for (it = mpPrograms.begin(); it != end; it++)
647     {
648     if (*it && i == Index)
649     {
650     (*it)->Acquire();
651     return *it;
652     }
653     i++;
654     }
655     return NULL;
656     }
657    
658     AkaiProgram* AkaiVolume::GetProgram(const String& rName)
659     {
660     if (mpPrograms.empty())
661     {
662     std::list<AkaiDirEntry> dummy;
663     ListPrograms(dummy);
664     }
665    
666     std::list<AkaiProgram*>::iterator it;
667     std::list<AkaiProgram*>::iterator end = mpPrograms.end();
668     for (it = mpPrograms.begin(); it != end; it++)
669     {
670     if (*it && rName == (*it)->GetDirEntry().mName)
671     {
672     (*it)->Acquire();
673     return *it;
674     }
675     }
676     return NULL;
677     }
678    
679     uint AkaiVolume::ListSamples(std::list<AkaiDirEntry>& rSamples)
680     {
681     rSamples.clear();
682     ReadDir();
683    
684     std::list<AkaiSample*>::iterator it;
685     std::list<AkaiSample*>::iterator end = mpSamples.end();
686     for (it = mpSamples.begin(); it != end; it++)
687     if (*it)
688     rSamples.push_back((*it)->GetDirEntry());
689     return (uint)rSamples.size();
690     }
691    
692     AkaiSample* AkaiVolume::GetSample(uint Index)
693     {
694     uint i = 0;
695    
696     if (mpSamples.empty())
697     {
698     std::list<AkaiDirEntry> dummy;
699     ListSamples(dummy);
700     }
701    
702     std::list<AkaiSample*>::iterator it;
703     std::list<AkaiSample*>::iterator end = mpSamples.end();
704     for (it = mpSamples.begin(); it != end; it++)
705     {
706     if (*it && i == Index)
707     {
708     (*it)->Acquire();
709     return *it;
710     }
711     i++;
712     }
713     return NULL;
714     }
715    
716     AkaiSample* AkaiVolume::GetSample(const String& rName)
717     {
718     if (mpSamples.empty())
719     {
720     std::list<AkaiDirEntry> dummy;
721     ListSamples(dummy);
722     }
723    
724     std::list<AkaiSample*>::iterator it;
725     std::list<AkaiSample*>::iterator end = mpSamples.end();
726     for (it = mpSamples.begin(); it != end; it++)
727     {
728     if (*it && rName == (*it)->GetDirEntry().mName)
729     {
730     (*it)->Acquire();
731     return *it;
732     }
733     }
734     return NULL;
735     }
736    
737     AkaiDirEntry AkaiVolume::GetDirEntry()
738     {
739     return mDirEntry;
740     }
741    
742     bool AkaiVolume::IsEmpty()
743     {
744     return ReadDir() == 0;
745     }
746    
747    
748     //////////////////////////////////
749     // AkaiPartition:
750     AkaiPartition::AkaiPartition(DiskImage* pDisk, AkaiDisk* pParent)
751     {
752     mpDisk = pDisk;
753     mpParent = pParent;
754     }
755    
756     AkaiPartition::~AkaiPartition()
757     {
758     std::list<AkaiVolume*>::iterator it;
759     std::list<AkaiVolume*>::iterator end = mpVolumes.end();
760     for (it = mpVolumes.begin(); it != end; it++)
761     if (*it)
762     (*it)->Release();
763     }
764    
765     uint AkaiPartition::ListVolumes(std::list<AkaiDirEntry>& rVolumes)
766     {
767     rVolumes.clear();
768     uint i;
769     if (mpVolumes.empty())
770     {
771     for (i = 0; i < AKAI_MAX_DIR_ENTRIES; i++)
772     {
773     AkaiDirEntry DirEntry;
774     ReadDirEntry(mpDisk, this, DirEntry, AKAI_ROOT_ENTRY_OFFSET, i);
775     DirEntry.mIndex = i;
776     if (DirEntry.mType == AKAI_TYPE_DIR_S1000 || DirEntry.mType == AKAI_TYPE_DIR_S3000)
777     {
778     AkaiVolume* pVolume = new AkaiVolume(mpDisk, this, DirEntry);
779     pVolume->Acquire();
780     if (!pVolume->IsEmpty())
781     {
782     mpVolumes.push_back(pVolume);
783     rVolumes.push_back(DirEntry);
784     }
785     else
786     pVolume->Release();
787     }
788     }
789     }
790     else
791     {
792     std::list<AkaiVolume*>::iterator it;
793     std::list<AkaiVolume*>::iterator end = mpVolumes.end();
794     for (it = mpVolumes.begin(); it != end; it++)
795     if (*it)
796     rVolumes.push_back((*it)->GetDirEntry());
797     }
798     return (uint)rVolumes.size();
799     }
800    
801     AkaiVolume* AkaiPartition::GetVolume(uint Index)
802     {
803     uint i = 0;
804    
805     if (mpVolumes.empty())
806     {
807     std::list<AkaiDirEntry> dummy;
808     ListVolumes(dummy);
809     }
810    
811     std::list<AkaiVolume*>::iterator it;
812     std::list<AkaiVolume*>::iterator end = mpVolumes.end();
813     for (it = mpVolumes.begin(); it != end; it++)
814     {
815     if (*it && i == Index)
816     {
817     (*it)->Acquire();
818     return *it;
819     }
820     i++;
821     }
822     return NULL;
823     }
824    
825     AkaiVolume* AkaiPartition::GetVolume(const String& rName)
826     {
827     if (mpVolumes.empty())
828     {
829     std::list<AkaiDirEntry> dummy;
830     ListVolumes(dummy);
831     }
832    
833     std::list<AkaiVolume*>::iterator it;
834     std::list<AkaiVolume*>::iterator end = mpVolumes.end();
835     for (it = mpVolumes.begin(); it != end; it++)
836     {
837     if (*it && rName == (*it)->GetDirEntry().mName)
838     {
839     (*it)->Acquire();
840     return *it;
841     }
842     }
843     return NULL;
844     }
845    
846     bool AkaiPartition::IsEmpty()
847     {
848     std::list<AkaiDirEntry> Volumes;
849     return ListVolumes(Volumes) == 0;
850     }
851    
852    
853     //////////////////////////////////
854     // AkaiDisk:
855     AkaiDisk::AkaiDisk(DiskImage* pDisk)
856     {
857     mpDisk = pDisk;
858     }
859    
860     AkaiDisk::~AkaiDisk()
861     {
862     std::list<AkaiPartition*>::iterator it;
863     std::list<AkaiPartition*>::iterator end = mpPartitions.end();
864     for (it = mpPartitions.begin(); it != end ; it++)
865     if (*it)
866     (*it)->Release();
867     }
868    
869     uint AkaiDisk::GetPartitionCount()
870     {
871     if (!mpPartitions.empty())
872     return (uint)mpPartitions.size();
873    
874     uint offset = 0;
875     uint16_t size = 0;
876     while (size != AKAI_PARTITION_END_MARK && size != 0x0fff && size != 0xffff
877     && size<30720 && mpPartitions.size()<9)
878     {
879     // printf("size: %x\t",size);
880     AkaiPartition* pPartition = new AkaiPartition(mpDisk,this);
881     pPartition->Acquire();
882     pPartition->SetOffset(offset);
883    
884     if (!pPartition->IsEmpty())
885     {
886     mpPartitions.push_back(pPartition); // Add this partitions' offset to the list.
887     }
888    
889     mpDisk->SetPos(offset);
890     if (!mpDisk->ReadInt16(&size))
891     return (uint)mpPartitions.size();
892     uint t = size;
893     offset += AKAI_BLOCK_SIZE * t;
894     // printf("new offset %d / size %d\n",offset,size);
895     }
896    
897     return (uint)mpPartitions.size();
898     }
899    
900     AkaiPartition* AkaiDisk::GetPartition(uint count)
901     {
902     std::list<AkaiPartition*>::iterator it;
903     std::list<AkaiPartition*>::iterator end = mpPartitions.end();
904     uint i = 0;
905     for (i = 0, it = mpPartitions.begin(); it != end && i != count; i++) it++;
906    
907     if (i != count || it == end)
908     return NULL;
909    
910     (*it)->Acquire();
911     return *it;
912     }
913    
914     /////////////////////////
915     // AkaiDiskElement
916    
917     int AkaiDiskElement::ReadFAT(DiskImage* pDisk, AkaiPartition* pPartition, int block)
918     {
919     int16_t value = 0;
920     pDisk->SetPos(pPartition->GetOffset()+AKAI_FAT_OFFSET + block*2);
921     pDisk->Read(&value, 2,1);
922     return value;
923     }
924    
925    
926     bool AkaiDiskElement::ReadDirEntry(DiskImage* pDisk, AkaiPartition* pPartition, AkaiDirEntry& rEntry, int block, int pos)
927     {
928     char buffer[13];
929    
930     if (block == AKAI_ROOT_ENTRY_OFFSET)
931     {
932     pDisk->SetPos(pPartition->GetOffset()+AKAI_DIR_ENTRY_OFFSET + pos * AKAI_DIR_ENTRY_SIZE);
933     pDisk->Read(buffer, 12, 1);
934     AkaiToAscii(buffer, 12);
935     rEntry.mName = buffer;
936    
937     pDisk->ReadInt16(&rEntry.mType);
938     pDisk->ReadInt16(&rEntry.mStart);
939     rEntry.mSize = 0;
940     return true;
941     }
942     else
943     {
944     if (pos < 341)
945     {
946     pDisk->SetPos(block * AKAI_BLOCK_SIZE + pos * AKAI_FILE_ENTRY_SIZE + pPartition->GetOffset());
947     }
948     else
949     {
950     int temp;
951     temp = ReadFAT(pDisk, pPartition, block);
952     pDisk->SetPos(pPartition->GetOffset()+temp * AKAI_BLOCK_SIZE + (pos - 341) * AKAI_FILE_ENTRY_SIZE);
953     }
954    
955     pDisk->Read(buffer, 12, 1);
956     AkaiToAscii(buffer, 12);
957     rEntry.mName = buffer;
958    
959     uint8_t t1,t2,t3;
960     pDisk->SetPos(4,akai_stream_curpos);
961     pDisk->Read(&t1, 1,1);
962     rEntry.mType = t1;
963    
964     pDisk->Read(&t1, 1,1);
965     pDisk->Read(&t2, 1,1);
966     pDisk->Read(&t3, 1,1);
967     rEntry.mSize = (unsigned char)t1 | ((unsigned char)t2 <<8) | ((unsigned char)t3<<16);
968    
969     pDisk->ReadInt16(&rEntry.mStart,1);
970     return true;
971     } // not root block
972     }
973    
974     void AkaiDiskElement::AkaiToAscii(char * buffer, int length)
975     {
976     int i;
977    
978     for (i = 0; i < length; i++)
979     {
980     if (buffer[i]>=0 && buffer[i]<=9)
981     buffer[i] +=48;
982     else if (buffer[i]==10)
983     buffer[i] = 32;
984     else if (buffer[i]>=11 && buffer[i]<=36)
985     buffer[i] = 64+(buffer[i]-10);
986     else
987     buffer[i] = 32;
988     }
989     buffer[length] = '\0';
990     while (length-- > 0 && buffer[length] == 32)
991     {
992     // This block intentionaly left blank :)
993     }
994     buffer[length+1] = '\0';
995     }
996    
997    
998     //////////////////////////////////
999     // DiskImage:
1000    
1001     DiskImage::DiskImage(const char* path)
1002     {
1003     Init();
1004     OpenStream(path);
1005     }
1006    
1007     #ifdef _CARBON_
1008     kern_return_t FindEjectableCDMedia( io_iterator_t *mediaIterator )
1009     {
1010     kern_return_t kernResult;
1011     mach_port_t masterPort;
1012     CFMutableDictionaryRef classesToMatch;
1013    
1014     kernResult = IOMasterPort( MACH_PORT_NULL, &masterPort );
1015     if ( KERN_SUCCESS != kernResult )
1016     {
1017     printf( "IOMasterPort returned %d\n", kernResult );
1018     }
1019    
1020     classesToMatch = IOServiceMatching( kIOCDMediaClass );
1021     if ( classesToMatch == NULL )
1022     {
1023     printf( "IOServiceMatching returned a NULL dictionary.\n" );
1024     }
1025     else
1026     {
1027     CFDictionarySetValue( classesToMatch, CFSTR( kIOMediaEjectableKey ), kCFBooleanTrue );
1028     }
1029    
1030     kernResult = IOServiceGetMatchingServices( masterPort, classesToMatch, mediaIterator );
1031     if ( KERN_SUCCESS != kernResult )
1032     {
1033     printf( "IOServiceGetMatchingServices returned %d\n", kernResult );
1034     }
1035    
1036     return kernResult;
1037     }
1038    
1039     kern_return_t GetBSDPath( io_iterator_t mediaIterator, char *bsdPath, CFIndex maxPathSize )
1040     {
1041     io_object_t nextMedia;
1042     kern_return_t kernResult = KERN_FAILURE;
1043    
1044     *bsdPath = '\0';
1045    
1046     nextMedia = IOIteratorNext( mediaIterator );
1047     if ( nextMedia )
1048     {
1049     CFTypeRef bsdPathAsCFString;
1050    
1051     bsdPathAsCFString = IORegistryEntryCreateCFProperty( nextMedia,
1052     CFSTR( kIOBSDNameKey ),
1053     kCFAllocatorDefault,
1054     0 );
1055     if ( bsdPathAsCFString )
1056     {
1057     size_t devPathLength;
1058    
1059     strcpy( bsdPath, _PATH_DEV );
1060     strcat( bsdPath, "r" );
1061    
1062     devPathLength = strlen( bsdPath );
1063    
1064     if ( CFStringGetCString( (__CFString*)bsdPathAsCFString,
1065     bsdPath + devPathLength,
1066     maxPathSize - devPathLength,
1067     kCFStringEncodingASCII ) )
1068     {
1069     printf( "BSD path: %s\n", bsdPath );
1070     kernResult = KERN_SUCCESS;
1071     }
1072    
1073     CFRelease( bsdPathAsCFString );
1074     }
1075     IOObjectRelease( nextMedia );
1076     }
1077    
1078     return kernResult;
1079     }
1080    
1081     struct _CDMSF
1082     {
1083     u_char minute;
1084     u_char second;
1085     u_char frame;
1086     };
1087    
1088     /* converting from minute-second to logical block entity */
1089     #define MSF_TO_LBA(msf) (((((msf).minute * 60UL) + (msf).second) * 75UL) + (msf).frame - 150)
1090    
1091     struct _CDTOC_Desc
1092     {
1093     u_char session;
1094     u_char ctrl_adr; /* typed to be machine and compiler independent */
1095     u_char tno;
1096     u_char point;
1097     struct _CDMSF address;
1098     u_char zero;
1099     struct _CDMSF p;
1100     };
1101    
1102     struct _CDTOC
1103     {
1104     u_short length; /* in native cpu endian */
1105     u_char first_session;
1106     u_char last_session;
1107     struct _CDTOC_Desc trackdesc[1];
1108     };
1109    
1110     static struct _CDTOC * ReadTOC (const char * devpath )
1111     {
1112     struct _CDTOC * toc_p = NULL;
1113     io_iterator_t iterator = 0;
1114     io_registry_entry_t service = 0;
1115     CFDictionaryRef properties = 0;
1116     CFDataRef data = 0;
1117     mach_port_t port = 0;
1118     char * devname;
1119     if (( devname = strrchr( devpath, '/' )) != NULL )
1120     {
1121     ++devname;
1122     }
1123     else
1124     {
1125     devname = ( char *) devpath;
1126     }
1127    
1128     if ( IOMasterPort(bootstrap_port, &port ) != KERN_SUCCESS )
1129     {
1130     printf( "IOMasterPort failed\n" ); goto Exit ;
1131     }
1132     if ( IOServiceGetMatchingServices( port, IOBSDNameMatching( port, 0, devname ),
1133     &iterator ) != KERN_SUCCESS )
1134     {
1135     printf( "IOServiceGetMatchingServices failed\n" ); goto Exit ;
1136     }
1137    
1138     char buffer[1024];
1139     IOObjectGetClass(iterator,buffer);
1140     printf("Service: %s\n",buffer);
1141    
1142    
1143     IOIteratorReset (iterator);
1144     service = IOIteratorNext( iterator );
1145    
1146     IOObjectRelease( iterator );
1147    
1148     iterator = 0;
1149     while ( service && !IOObjectConformsTo( service, "IOCDMedia" ))
1150     {
1151     char buffer[1024];
1152     IOObjectGetClass(service,buffer);
1153     printf("Service: %s\n",buffer);
1154    
1155     if ( IORegistryEntryGetParentIterator( service, kIOServicePlane, &iterator ) != KERN_SUCCESS )
1156     {
1157     printf( "IORegistryEntryGetParentIterator failed\n" );
1158     goto Exit ;
1159     }
1160    
1161     IOObjectRelease( service );
1162     service = IOIteratorNext( iterator );
1163     IOObjectRelease( iterator );
1164    
1165     }
1166     if ( service == NULL )
1167     {
1168     printf( "CD media not found\n" ); goto Exit ;
1169     }
1170     if ( IORegistryEntryCreateCFProperties( service, (__CFDictionary **) &properties,
1171     kCFAllocatorDefault,
1172     kNilOptions ) != KERN_SUCCESS )
1173     {
1174     printf( "IORegistryEntryGetParentIterator failed\n" ); goto Exit ;
1175     }
1176    
1177     data = (CFDataRef) CFDictionaryGetValue( properties, CFSTR( "TOC" ) );
1178     if ( data == NULL )
1179     {
1180     printf( "CFDictionaryGetValue failed\n" ); goto Exit ;
1181     }
1182     else
1183     {
1184    
1185     CFRange range;
1186     CFIndex buflen;
1187    
1188     buflen = CFDataGetLength( data ) + 1;
1189     range = CFRangeMake( 0, buflen );
1190     toc_p = ( struct _CDTOC *) malloc( buflen );
1191     if ( toc_p == NULL )
1192     {
1193     printf( "Out of memory\n" ); goto Exit ;
1194     }
1195     else
1196     {
1197     CFDataGetBytes( data, range, ( unsigned char *) toc_p );
1198     }
1199    
1200     /*
1201     fprintf( stderr, "Table of contents\n length %d first %d last %d\n",
1202     toc_p->length, toc_p->first_session, toc_p->last_session );
1203     */
1204    
1205     CFRelease( properties );
1206    
1207     }
1208     Exit :
1209     if ( service )
1210     {
1211     IOObjectRelease( service );
1212     }
1213    
1214     return toc_p;
1215     }
1216     #endif // _CARBON_
1217    
1218     DiskImage::DiskImage(int disk)
1219     {
1220     Init();
1221     #ifdef _WIN32_
1222     char buffer[1024];
1223     sprintf(buffer,"%c:\\",'A'+disk);
1224     mSize = GetFileSize(buffer,NULL);
1225    
1226     sprintf(buffer,"\\\\.\\%c:",'a'+disk);
1227     mFile = CreateFile(buffer, GENERIC_READ,0,NULL,OPEN_EXISTING, FILE_FLAG_RANDOM_ACCESS,NULL);
1228    
1229     DWORD junk;
1230     DISK_GEOMETRY dg;
1231     DISK_GEOMETRY* pdg = &dg;
1232     BOOL res = DeviceIoControl(mFile,
1233     IOCTL_DISK_GET_DRIVE_GEOMETRY,
1234     NULL, 0,
1235     pdg, sizeof(*pdg),
1236     &junk,
1237     NULL);
1238    
1239     if (res)
1240     {
1241     mSize = dg.BytesPerSector * dg.SectorsPerTrack * dg.TracksPerCylinder * dg.Cylinders.LowPart;
1242     mClusterSize = dg.BytesPerSector;
1243     }
1244     #elif defined _CARBON_
1245     kern_return_t kernResult;
1246     io_iterator_t mediaIterator;
1247     char bsdPath[ MAXPATHLEN ];
1248     kernResult = FindEjectableCDMedia( &mediaIterator );
1249     kernResult = GetBSDPath( mediaIterator, bsdPath, sizeof( bsdPath ) );
1250     if ( bsdPath[ 0 ] != '\0' )
1251     {
1252     strcpy(bsdPath,"/dev/rdisk1s0");
1253    
1254     struct _CDTOC * toc = ReadTOC( bsdPath );
1255     if ( toc )
1256     {
1257     size_t toc_entries = ( toc->length - 2 ) / sizeof (struct _CDTOC_Desc );
1258    
1259     int start_sector = -1;
1260     int data_track = -1;
1261     // Iterate through the list backward. Pick the first data track and
1262     // get the address of the immediately previous (or following depending
1263     // on how you look at it). The difference in the sector numbers
1264     // is returned as the sized of the data track.
1265     for (int i=toc_entries - 1; i>=0; i-- )
1266     {
1267     if ( start_sector != -1 )
1268     {
1269     start_sector = MSF_TO_LBA(toc->trackdesc[i].p) - start_sector;
1270     break ;
1271    
1272     }
1273     if (( toc->trackdesc[i].ctrl_adr >> 4) != 1 )
1274     continue ;
1275     if ( toc->trackdesc[i].ctrl_adr & 0x04 )
1276     {
1277     data_track = toc->trackdesc[i].point;
1278     start_sector = MSF_TO_LBA(toc->trackdesc[i].p);
1279     }
1280     }
1281    
1282     free( toc );
1283     if ( start_sector == -1 )
1284     {
1285     start_sector = 0;
1286     }
1287     }
1288     // mSize = start_sector;
1289     // printf("size %d\n",mSize);
1290    
1291    
1292     mFile = open(bsdPath,O_RDONLY);
1293     if (!mFile)
1294     printf("Error while opening file: %s\n",bsdPath);
1295     else
1296     {
1297     printf("opened file: %s\n",bsdPath);
1298    
1299     mSize = lseek(mFile,1000000000,SEEK_SET);
1300     printf("size %d\n",mSize);
1301     lseek(mFile,0,SEEK_SET);
1302    
1303     mSize = 700 * 1024 * 1024;
1304    
1305     }
1306     }
1307     if ( mediaIterator )
1308     {
1309     IOObjectRelease( mediaIterator );
1310     }
1311     #elif LINUX
1312     OpenStream("/dev/cdrom");
1313     #endif
1314     }
1315    
1316     void DiskImage::Init()
1317     {
1318     mFile = 0;
1319     mPos = 0;
1320     mCluster = (uint)-1;
1321     mStartFrame = -1;
1322     mEndFrame = -1;
1323     #ifdef _WIN32_
1324     mpCache = (char*) VirtualAlloc(NULL,mClusterSize,MEM_COMMIT,PAGE_READWRITE);
1325     #else
1326     mpCache = NULL; // we allocate the cache later when we know what type of media we access
1327     #endif
1328     }
1329    
1330     DiskImage::~DiskImage()
1331     {
1332     #ifdef _WIN32_
1333     if (mFile != INVALID_HANDLE_VALUE)
1334     {
1335     CloseHandle(mFile);
1336     }
1337     #elif defined _CARBON_ || LINUX
1338     if (mFile)
1339     {
1340     close(mFile);
1341     }
1342     #endif
1343     if (mpCache)
1344     {
1345     #ifdef _WIN32_
1346     VirtualFree(mpCache, 0, MEM_RELEASE);
1347     #elif defined _CARBON_ || LINUX
1348     free(mpCache);
1349     #endif
1350     }
1351     }
1352    
1353     akai_stream_state_t DiskImage::GetState() const
1354     {
1355     if (!mFile) return akai_stream_closed;
1356     if (mPos > mSize) return akai_stream_end_reached;
1357     return akai_stream_ready;
1358     }
1359    
1360     int DiskImage::GetPos() const
1361     {
1362     return mPos;
1363     }
1364    
1365     int DiskImage::SetPos(int Where, akai_stream_whence_t Whence)
1366     {
1367     // printf("setpos %d\n",Where);
1368     int w = Where;
1369     switch (Whence)
1370     {
1371     case akai_stream_start:
1372     mPos = w;
1373     break;
1374     /*case eStreamRewind:
1375     w = -w;*/
1376     case akai_stream_curpos:
1377     mPos += w;
1378     break;
1379     case akai_stream_end:
1380     mPos = mSize - w;
1381     break;
1382     }
1383     // if (mPos > mSize)
1384     // mPos = mSize;
1385     if (mPos < 0)
1386     mPos = 0;
1387     return mPos;
1388     }
1389    
1390     int DiskImage::Available (uint WordSize)
1391     {
1392     return (mSize-mPos)/WordSize;
1393     }
1394    
1395     int DiskImage::Read(void* pData, uint WordCount, uint WordSize)
1396     {
1397     int readbytes = 0;
1398     int sizetoread = WordCount * WordSize;
1399    
1400     while (sizetoread > 0) {
1401     if (mSize <= mPos) return readbytes / WordSize;
1402     int requestedCluster = (mRegularFile) ? mPos / mClusterSize
1403     : mPos / mClusterSize + mStartFrame;
1404     if (mCluster != requestedCluster) { // read the requested cluster into cache
1405     mCluster = requestedCluster;
1406     #ifdef _WIN32_
1407     if (mCluster * mClusterSize != SetFilePointer(mFile, mCluster * mClusterSize, NULL, FILE_BEGIN)) {
1408     printf("ERROR: couldn't seek device!\n");
1409     if ((readbytes > 0) && (mEndian != eEndianNative)) {
1410     switch (WordSize) {
1411     case 2: bswap_16_s ((uint16*)pData, readbytes); break;
1412     case 4: bswap_32_s ((uint32*)pData, readbytes); break;
1413     case 8: bswap_64_s ((uint64*)pData, readbytes); break;
1414     }
1415     }
1416     return readbytes / WordSize;
1417     }
1418     DWORD size;
1419     ReadFile(mFile, mpCache, mClusterSize, &size, NULL);
1420     #elif defined _CARBON_ || LINUX
1421     if (mCluster * mClusterSize != lseek(mFile, mCluster * mClusterSize, SEEK_SET))
1422     return readbytes / WordSize;
1423     // printf("trying to read %d bytes from device!\n",mClusterSize);
1424     int size = read(mFile, mpCache, mClusterSize);
1425     // printf("read %d bytes from device!\n",size);
1426     #endif
1427     }
1428     // printf("read %d bytes at pos %d\n",WordCount*WordSize,mPos);
1429    
1430     int currentReadSize = sizetoread;
1431     int posInCluster = mPos % mClusterSize;
1432     if (currentReadSize > mClusterSize - posInCluster) // restrict to this current cached cluster.
1433     currentReadSize = mClusterSize - posInCluster;
1434    
1435     memcpy((uint8_t*)pData + readbytes, mpCache + posInCluster, currentReadSize);
1436    
1437     mPos += currentReadSize;
1438     readbytes += currentReadSize;
1439     sizetoread -= currentReadSize;
1440     // printf("new pos %d\n",mPos);
1441     }
1442    
1443     #if 0
1444     if ((readbytes > 0) && (mEndian != eEndianNative))
1445     switch (WordSize)
1446     {
1447     case 2: bswap_16_s ((uint16_t*)pData, readbytes); break;
1448     case 4: bswap_32_s ((uint32_t*)pData, readbytes); break;
1449     case 8: bswap_64_s ((uint64_t*)pData, readbytes); break;
1450     }
1451     #endif
1452    
1453     return readbytes / WordSize;
1454     }
1455    
1456     void DiskImage::ReadInt8(uint8_t* pData, uint WordCount) {
1457     Read(pData, WordCount, 1);
1458     }
1459    
1460     void DiskImage::ReadInt16(uint16_t* pData, uint WordCount) {
1461     int i;
1462     for (i = 0; i < WordCount; i++) {
1463     *(pData + i) = ReadInt16();
1464     }
1465     }
1466    
1467     void DiskImage::ReadInt32(uint32_t* pData, uint WordCount) {
1468     int i;
1469     for (i = 0; i < WordCount; i++) {
1470     *(pData + i) = ReadInt32();
1471     }
1472     }
1473    
1474     int DiskImage::ReadInt8(uint8_t* pData) {
1475     return Read(pData, 1, 1);
1476     }
1477    
1478     int DiskImage::ReadInt16(uint16_t* pData) {
1479     int result = Read(pData, 1, 2);
1480     #if WORDS_BIGENDIAN
1481     swapBytes_16(pData);
1482     #endif
1483     return result;
1484     }
1485    
1486     int DiskImage::ReadInt32(uint32_t* pData) {
1487     int result = Read(pData, 1, 4);
1488     #if WORDS_BIGENDIAN
1489     swapBytes_32(pData);
1490     #endif
1491     return result;
1492     }
1493    
1494     uint8_t DiskImage::ReadInt8()
1495     {
1496     uint8_t word;
1497     Read(&word,1,1);
1498     return word;
1499     }
1500    
1501     uint16_t DiskImage::ReadInt16()
1502     {
1503     uint16_t word;
1504     Read(&word,1,2);
1505     #if WORDS_BIGENDIAN
1506     swapBytes_16(&word);
1507     #endif
1508     return word;
1509     }
1510    
1511     uint32_t DiskImage::ReadInt32()
1512     {
1513     uint32_t word;
1514     Read(&word,1,4);
1515     #if WORDS_BIGENDIAN
1516     swapBytes_32(&word);
1517     #endif
1518     return word;
1519     }
1520    
1521     void DiskImage::OpenStream(const char* path) {
1522     #ifdef _WIN32_
1523     mFile = CreateFile(path, GENERIC_READ,0,NULL,OPEN_EXISTING, FILE_FLAG_RANDOM_ACCESS,NULL);
1524     BY_HANDLE_FILE_INFORMATION FileInfo;
1525     GetFileInformationByHandle(mFile,&FileInfo);
1526     mSize = FileInfo.nFileSizeLow;
1527     #elif _CARBON_ || LINUX
1528     struct stat filestat;
1529     stat(path,&filestat);
1530     mFile = open(path, O_RDONLY | O_NONBLOCK);
1531     if (mFile <= 0) {
1532     printf("Can't open %s\n", path);
1533     mFile = 0;
1534     return;
1535     }
1536     // TODO: we should also check here if 'path' is a link or something
1537     if (S_ISREG(filestat.st_mode)) { // regular file
1538     printf("Using regular Akai image file.\n");
1539     mRegularFile = true;
1540     mSize = filestat.st_size;
1541     mClusterSize = DISK_CLUSTER_SIZE;
1542     mpCache = (char*) malloc(mClusterSize);
1543     }
1544     else { // CDROM
1545     mRegularFile = false;
1546     mClusterSize = CD_FRAMESIZE;
1547     mpCache = (char*) malloc(mClusterSize);
1548    
1549     struct cdrom_tochdr tochdr;
1550     struct cdrom_tocentry tocentry;
1551     int prev_addr = 0;
1552     if (ioctl(mFile, CDROMREADTOCHDR, (unsigned long)&tochdr) < 0) {
1553     printf("Trying to read TOC of %s failed\n", path);
1554     close(mFile);
1555     mFile = 0;
1556     return;
1557     }
1558     printf("Total tracks: %d\n", tochdr.cdth_trk1);
1559    
1560     /* we access the CD with logical blocks as entity */
1561     tocentry.cdte_format = CDROM_LBA;
1562    
1563     int firstDataTrack = -1;
1564     int start, end, length;
1565    
1566     /* we pick up the lowest data track by iterating backwards, starting with Lead Out */
1567     for (int t = tochdr.cdth_trk1; t >= 0; t--) {
1568     tocentry.cdte_track = (t == tochdr.cdth_trk1) ? CDROM_LEADOUT : t + 1;
1569     if (ioctl(mFile, CDROMREADTOCENTRY, (unsigned long)&tocentry) < 0){
1570     printf("Failed to read TOC entry for track %d\n", tocentry.cdte_track);
1571     close(mFile);
1572     mFile = 0;
1573     return;
1574     }
1575     if (tocentry.cdte_track == CDROM_LEADOUT) {
1576     printf("Lead Out: Start(LBA)=%d\n", tocentry.cdte_addr.lba);
1577     }
1578     else {
1579     printf("Track %d: Start(LBA)=%d End(LBA)=%d Length(Blocks)=%d ",
1580     tocentry.cdte_track, tocentry.cdte_addr.lba, prev_addr - 1, prev_addr - tocentry.cdte_addr.lba);
1581     if (tocentry.cdte_ctrl & CDROM_DATA_TRACK) {
1582     printf("Type: Data\n");
1583     firstDataTrack = tocentry.cdte_track;
1584     start = tocentry.cdte_addr.lba;
1585     end = prev_addr - 1;
1586     length = prev_addr - tocentry.cdte_addr.lba;
1587     }
1588     else printf("Type: Audio\n");
1589     }
1590     prev_addr = tocentry.cdte_addr.lba;
1591     }
1592    
1593     if (firstDataTrack == -1) {
1594     printf("Sorry, no data track found on %s\n", path);
1595     close(mFile);
1596     mFile = 0;
1597     return;
1598     }
1599    
1600     printf("Ok, I'll pick track %d\n", firstDataTrack);
1601     mStartFrame = start;
1602     mEndFrame = end;
1603     mSize = length * CD_FRAMESIZE;
1604     } // CDROM
1605     #endif
1606     }
1607    
1608     bool DiskImage::WriteImage(const char* path)
1609     {
1610     #if _CARBON_ || LINUX
1611     const uint bufferSize = 524288; // 512 kB
1612     int fOut = open(path, O_WRONLY | O_NONBLOCK | O_CREAT | O_TRUNC);
1613     if (mFile <= 0) {
1614     printf("Can't open output file %s\n", path);
1615     return false;
1616     }
1617     uint8_t* pBuffer = new uint8_t[bufferSize];
1618     SetPos(0);
1619     while (Available() > 0) {
1620     int readBytes = Read(pBuffer,bufferSize,1);
1621     if (readBytes > 0) write(fOut,pBuffer,readBytes);
1622     }
1623     delete[] pBuffer;
1624     close(fOut);
1625     return true;
1626     #endif // _CARBON_ || LINUX
1627     }
1628    
1629     inline void DiskImage::swapBytes_16(void* Word) {
1630     uint8_t byteCache;
1631     byteCache = *((uint8_t*) Word);
1632     *((uint8_t*) Word) = *((uint8_t*) Word + 1);
1633     *((uint8_t*) Word + 1) = byteCache;
1634     }
1635    
1636     inline void DiskImage::swapBytes_32(void* Word) {
1637     uint8_t byteCache;
1638     byteCache = *((uint8_t*) Word);
1639     *((uint8_t*) Word) = *((uint8_t*) Word + 3);
1640     *((uint8_t*) Word + 3) = byteCache;
1641     byteCache = *((uint8_t*) Word + 1);
1642     *((uint8_t*) Word + 1) = *((uint8_t*) Word + 2);
1643     *((uint8_t*) Word + 2) = byteCache;
1644     }

Properties

Name Value
svn:executable *

  ViewVC Help
Powered by ViewVC