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