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

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

Parent Directory Parent Directory | Revision Log Revision Log


Revision 2572 - (show 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 /*
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