31 #if defined(_CARBON_) || defined(__APPLE__)
32 # if defined (__GNUC__) && (__GNUC__ >= 4)
33 # include <sys/disk.h>
35 # include <dev/disk.h>
38 #include <sys/types.h>
41 #if defined(_CARBON_) || defined(__APPLE__)
43 #include <sys/ioctl.h>
44 #include <sys/param.h>
45 #include <IOKit/IOKitLib.h>
46 #include <IOKit/IOBSD.h>
47 #include <IOKit/storage/IOMediaBSDClient.h>
48 #include <IOKit/storage/IOMedia.h>
49 #include <IOKit/storage/IOCDMedia.h>
50 #include <IOKit/storage/IOCDTypes.h>
51 #include <CoreFoundation/CoreFoundation.h>
54 #if defined(_CARBON_) || defined(__APPLE__)
66 #define MSF_TO_LBA(msf) \
67 (((((msf).minute * 60UL) + (msf).second) * 75UL) + (msf).frame - 150)
74 struct _CDMSF address;
83 struct _CDTOC_Desc trackdesc[1];
93 static kern_return_t FindEjectableCDMedia(io_iterator_t *mediaIterator) {
94 kern_return_t kernResult;
95 CFMutableDictionaryRef classesToMatch;
98 classesToMatch = IOServiceMatching(kIOCDMediaClass);
99 if (classesToMatch == NULL) {
100 printf(
"IOServiceMatching returned a NULL dictionary.\n");
102 CFDictionarySetValue(classesToMatch, CFSTR(kIOMediaEjectableKey), kCFBooleanTrue);
107 kernResult = IOServiceGetMatchingServices(kIOMasterPortDefault, classesToMatch, mediaIterator);
114 static kern_return_t GetBSDPath(io_iterator_t mediaIterator,
char *bsdPath, CFIndex maxPathSize) {
115 io_object_t nextMedia;
116 kern_return_t kernResult = KERN_FAILURE;
120 nextMedia = IOIteratorNext(mediaIterator);
122 CFTypeRef bsdPathAsCFString;
124 bsdPathAsCFString = IORegistryEntryCreateCFProperty(nextMedia,
125 CFSTR(kIOBSDNameKey),
128 if (bsdPathAsCFString) {
129 strlcpy(bsdPath, _PATH_DEV, maxPathSize);
135 strlcat(bsdPath,
"r", maxPathSize);
137 size_t devPathLength = strlen(bsdPath);
139 if (CFStringGetCString((CFStringRef)bsdPathAsCFString,
140 bsdPath + devPathLength,
141 maxPathSize - devPathLength,
142 kCFStringEncodingUTF8)) {
143 printf(
"BSD path: %s\n", bsdPath);
144 kernResult = KERN_SUCCESS;
147 CFRelease(bsdPathAsCFString);
150 IOObjectRelease(nextMedia);
215 static struct _CDTOC * ReadTOC(
const char *devpath) {
216 struct _CDTOC * toc_p = NULL;
217 io_iterator_t iterator = 0;
218 io_registry_entry_t service = 0;
219 CFDictionaryRef properties = 0;
221 mach_port_t port = 0;
224 if ((devname = strrchr(devpath,
'/')) != NULL) {
227 devname = (
char *) devpath;
230 if (IOMasterPort(bootstrap_port, &port) != KERN_SUCCESS) {
231 fprintf(stderr,
"IOMasterPort failed\n");
235 if (IOServiceGetMatchingServices(port, IOBSDNameMatching(port, 0, devname),
236 &iterator) != KERN_SUCCESS) {
237 fprintf(stderr,
"IOServiceGetMatchingServices failed\n");
241 service = IOIteratorNext(iterator);
243 IOObjectRelease(iterator);
247 while (service && !IOObjectConformsTo(service,
"IOCDMedia")) {
248 if (IORegistryEntryGetParentIterator(service, kIOServicePlane,
249 &iterator) != KERN_SUCCESS)
251 fprintf(stderr,
"IORegistryEntryGetParentIterator failed\n");
255 IOObjectRelease(service);
256 service = IOIteratorNext(iterator);
257 IOObjectRelease(iterator);
261 fprintf(stderr,
"CD media not found\n");
265 if (IORegistryEntryCreateCFProperties(service, (__CFDictionary **) &properties,
267 kNilOptions) != KERN_SUCCESS)
269 fprintf(stderr,
"IORegistryEntryGetParentIterator failed\n");
273 data = (CFDataRef) CFDictionaryGetValue(properties, CFSTR(kIOCDMediaTOCKey));
275 fprintf(stderr,
"CFDictionaryGetValue failed\n");
281 buflen = CFDataGetLength(data) + 1;
282 range = CFRangeMake(0, buflen);
283 toc_p = (
struct _CDTOC *) malloc(buflen);
285 fprintf(stderr,
"Out of memory\n");
288 CFDataGetBytes(data, range, (
unsigned char *) toc_p);
296 CFRelease(properties);
302 IOObjectRelease(service);
312 AkaiSample::AkaiSample(
DiskImage* pDisk,
AkaiVolume* pParent,
const AkaiDirEntry& DirEntry)
313 : AkaiDiskElement(pDisk->GetPos())
317 mDirEntry = DirEntry;
326 AkaiSample::~AkaiSample()
332 AkaiDirEntry AkaiSample::GetDirEntry()
337 bool AkaiSample::LoadSampleData()
344 mpDisk->SetPos(mImageOffset);
345 mpSamples = (int16_t*) malloc(mNumberOfSamples *
sizeof(int16_t));
349 mpDisk->ReadInt16((uint16_t*)mpSamples, mNumberOfSamples);
353 void AkaiSample::ReleaseSampleData()
361 int AkaiSample::SetPos(
int Where, akai_stream_whence_t Whence)
363 if (!mHeaderOK)
return -1;
367 case akai_stream_start:
372 case akai_stream_curpos:
375 case akai_stream_end:
376 mPos = mNumberOfSamples - w;
379 if (mPos > mNumberOfSamples) mPos = mNumberOfSamples;
380 if (mPos < 0) mPos = 0;
384 int AkaiSample::Read(
void* pBuffer, uint SampleCount)
386 if (!mHeaderOK)
return 0;
388 if (mPos + SampleCount > mNumberOfSamples) SampleCount = mNumberOfSamples - mPos;
390 mpDisk->SetPos(mImageOffset + mPos * 2);
391 mpDisk->ReadInt16((uint16_t*)pBuffer, SampleCount);
395 bool AkaiSample::LoadHeader()
400 mpDisk->SetPos(mpParent->GetParent()->GetOffset() + mDirEntry.mStart * AKAI_BLOCK_SIZE );
405 if (mpDisk->ReadInt8() != AKAI_SAMPLE_ID)
410 mMidiRootNote = mpDisk->ReadInt8();
413 mpDisk->Read(buffer, 12, 1);
414 AkaiToAscii(buffer, 12);
420 mActiveLoops = mpDisk->ReadInt8();
422 mFirstActiveLoop = mpDisk->ReadInt8();
427 mLoopMode = mpDisk->ReadInt8();
429 mTuneCents = mpDisk->ReadInt8();
431 mTuneSemitones = mpDisk->ReadInt8();
439 mNumberOfSamples = mpDisk->ReadInt32();
441 mStartMarker = mpDisk->ReadInt32();
443 mEndMarker = mpDisk->ReadInt32();
454 mLoops[i].Load(mpDisk);
458 mSamplingFrequency = mpDisk->ReadInt16();
460 mLoopTuneOffset = mpDisk->ReadInt8();
462 mImageOffset = mpParent->GetParent()->GetOffset() + mDirEntry.mStart * AKAI_BLOCK_SIZE + 150;
465 return (mHeaderOK =
true);
468 bool AkaiSampleLoop::Load(
DiskImage* pDisk)
471 mMarker = pDisk->ReadInt32();
473 mFineLength = pDisk->ReadInt16();
475 mCoarseLength = pDisk->ReadInt32();
477 mTime = pDisk->ReadInt16();
483 AkaiProgram::AkaiProgram(
DiskImage* pDisk,
AkaiVolume* pParent,
const AkaiDirEntry& DirEntry)
484 : AkaiDiskElement(pDisk->GetPos())
488 mDirEntry = DirEntry;
493 AkaiProgram::~AkaiProgram()
496 delete[] mpKeygroups;
499 AkaiDirEntry AkaiProgram::GetDirEntry()
504 bool AkaiProgram::Load()
507 uint temppos = mpDisk->GetPos();
508 mpDisk->SetPos(mpParent->GetParent()->GetOffset() + mDirEntry.mStart * AKAI_BLOCK_SIZE );
512 uint8_t ProgID = mpDisk->ReadInt8();
513 if (ProgID != AKAI_PROGRAM_ID)
515 mpDisk->SetPos(temppos);
522 mpDisk->
Read(buffer, 12, 1);
523 AkaiToAscii(buffer, 12);
526 mMidiProgramNumber = mpDisk->ReadInt8();
528 mMidiChannel = mpDisk->ReadInt8();
530 mPolyphony = mpDisk->ReadInt8();
532 mPriority = mpDisk->ReadInt8();
534 mLowKey = mpDisk->ReadInt8();
536 mHighKey = mpDisk->ReadInt8();
538 mOctaveShift = mpDisk->ReadInt8();
540 mAuxOutputSelect = mpDisk->ReadInt8();
542 mMixOutputSelect = mpDisk->ReadInt8();
544 mMixPan = mpDisk->ReadInt8();
546 mVolume = mpDisk->ReadInt8();
548 mVelocityToVolume = mpDisk->ReadInt8();
550 mKeyToVolume = mpDisk->ReadInt8();
552 mPressureToVolume = mpDisk->ReadInt8();
554 mPanLFORate = mpDisk->ReadInt8();
556 mPanLFODepth = mpDisk->ReadInt8();
558 mPanLFODelay = mpDisk->ReadInt8();
560 mKeyToPan = mpDisk->ReadInt8();
562 mLFORate = mpDisk->ReadInt8();
564 mLFODepth = mpDisk->ReadInt8();
566 mLFODelay = mpDisk->ReadInt8();
568 mModulationToLFODepth = mpDisk->ReadInt8();
570 mPressureToLFODepth = mpDisk->ReadInt8();
572 mVelocityToLFODepth = mpDisk->ReadInt8();
574 mBendToPitch = mpDisk->ReadInt8();
576 mPressureToPitch = mpDisk->ReadInt8();
578 mKeygroupCrossfade = mpDisk->ReadInt8()?
true:
false;
580 mNumberOfKeygroups = mpDisk->ReadInt8();
585 for (i = 0; i<11; i++)
586 mKeyTemperament[i] = mpDisk->ReadInt8();
588 mFXOutput = mpDisk->ReadInt8()?
true:
false;
590 mModulationToPan = mpDisk->ReadInt8();
592 mStereoCoherence = mpDisk->ReadInt8()?
true:
false;
594 mLFODesync = mpDisk->ReadInt8()?
true:
false;
596 mPitchLaw = mpDisk->ReadInt8();
598 mVoiceReassign = mpDisk->ReadInt8();
600 mSoftpedToVolume = mpDisk->ReadInt8();
602 mSoftpedToAttack = mpDisk->ReadInt8();
604 mSoftpedToFilter = mpDisk->ReadInt8();
606 mSoftpedToTuneCents = mpDisk->ReadInt8();
608 mSoftpedToTuneSemitones = mpDisk->ReadInt8();
610 mKeyToLFORate = mpDisk->ReadInt8();
612 mKeyToLFODepth = mpDisk->ReadInt8();
614 mKeyToLFODelay = mpDisk->ReadInt8();
616 mVoiceOutputScale = mpDisk->ReadInt8();
618 mStereoOutputScale = mpDisk->ReadInt8();
623 delete[] mpKeygroups;
624 mpKeygroups =
new AkaiKeygroup[mNumberOfKeygroups];
625 for (i = 0; i < mNumberOfKeygroups; i++)
628 mpDisk->SetPos(mpParent->GetParent()->GetOffset() + mDirEntry.mStart * AKAI_BLOCK_SIZE + 150 * (i+1));
629 if (!mpKeygroups[i].Load(mpDisk))
631 mpDisk->SetPos(temppos);
636 mpDisk->SetPos(temppos);
640 uint AkaiProgram::ListSamples(std::list<String>& rSamples)
645 AkaiSample* AkaiProgram::GetSample(uint Index)
650 AkaiSample* AkaiProgram::GetSample(
const String& rName)
656 bool AkaiKeygroup::Load(
DiskImage* pDisk)
662 if (pDisk->ReadInt8() != AKAI_KEYGROUP_ID)
667 mLowKey = pDisk->ReadInt8();
669 mHighKey = pDisk->ReadInt8();
671 mTuneCents = pDisk->ReadInt8();
673 mTuneSemitones = pDisk->ReadInt8();
675 mFilter = pDisk->ReadInt8();
677 mKeyToFilter = pDisk->ReadInt8();
679 mVelocityToFilter = pDisk->ReadInt8();
681 mPressureToFilter = pDisk->ReadInt8();
683 mEnveloppe2ToFilter = pDisk->ReadInt8();
702 mEnveloppes[i].Load(pDisk);
705 mVelocityToEnveloppe2ToFilter = pDisk->ReadInt8();
707 mEnveloppe2ToPitch = pDisk->ReadInt8();
709 mVelocityZoneCrossfade = pDisk->ReadInt8()?
true:
false;
711 mVelocityZoneUsed = pDisk->ReadInt8();
740 mSamples[i].Load(pDisk);
743 mBeatDetune = pDisk->ReadInt8();
745 mHoldAttackUntilLoop = pDisk->ReadInt8()?
true:
false;
748 mSampleKeyTracking[i] = pDisk->ReadInt8()?
true:
false;
751 mSampleAuxOutOffset[i] = pDisk->ReadInt8();
754 mVelocityToSampleStart[i] = pDisk->ReadInt8();
757 mVelocityToVolumeOffset[i] = pDisk->ReadInt8();
763 bool AkaiEnveloppe::Load(
DiskImage* pDisk)
766 mAttack = pDisk->ReadInt8();
768 mDecay = pDisk->ReadInt8();
770 mSustain = pDisk->ReadInt8();
772 mRelease = pDisk->ReadInt8();
774 mVelocityToAttack = pDisk->ReadInt8();
776 mVelocityToRelease = pDisk->ReadInt8();
778 mOffVelocityToRelease = pDisk->ReadInt8();
780 mKeyToDecayAndRelease = pDisk->ReadInt8();
784 bool AkaiKeygroupSample::Load(
DiskImage* pDisk)
788 pDisk->
Read(buffer, 12, 1);
789 AkaiToAscii(buffer, 12);
793 mLowLevel = pDisk->ReadInt8();
828 mDirEntry = DirEntry;
830 if (mDirEntry.mType != AKAI_TYPE_DIR_S1000 && mDirEntry.mType != AKAI_TYPE_DIR_S3000)
832 printf(
"Creating Unknown Volume type! %d\n",mDirEntry.mType);
834 OutputDebugString(
"Creating Unknown Volume type!\n");
839 AkaiVolume::~AkaiVolume()
842 std::list<AkaiProgram*>::iterator it;
843 std::list<AkaiProgram*>::iterator end = mpPrograms.end();
844 for (it = mpPrograms.begin(); it != end; it++)
850 std::list<AkaiSample*>::iterator it;
851 std::list<AkaiSample*>::iterator end = mpSamples.end();
852 for (it = mpSamples.begin(); it != end; it++)
858 uint AkaiVolume::ReadDir()
861 if (mpPrograms.empty())
863 uint maxfiles = ReadFAT(mpDisk, mpParent,mDirEntry.mStart) ? AKAI_MAX_FILE_ENTRIES_S1000 : AKAI_MAX_FILE_ENTRIES_S3000;
864 for (i = 0; i < maxfiles; i++)
866 AkaiDirEntry DirEntry;
867 ReadDirEntry(mpDisk, mpParent, DirEntry, mDirEntry.mStart, i);
869 if (DirEntry.mType ==
'p')
873 mpPrograms.push_back(pProgram);
875 else if (DirEntry.mType ==
's')
877 AkaiSample* pSample =
new AkaiSample(mpDisk,
this, DirEntry);
879 mpSamples.push_back(pSample);
883 return (uint)(mpPrograms.size() + mpSamples.size());
886 uint AkaiVolume::ListPrograms(std::list<AkaiDirEntry>& rPrograms)
891 std::list<AkaiProgram*>::iterator it;
892 std::list<AkaiProgram*>::iterator end = mpPrograms.end();
893 for (it = mpPrograms.begin(); it != end; it++)
895 rPrograms.push_back((*it)->GetDirEntry());
896 return (uint)rPrograms.size();
903 if (mpPrograms.empty())
905 std::list<AkaiDirEntry> dummy;
909 std::list<AkaiProgram*>::iterator it;
910 std::list<AkaiProgram*>::iterator end = mpPrograms.end();
911 for (it = mpPrograms.begin(); it != end; it++)
913 if (*it && i == Index)
923 AkaiProgram* AkaiVolume::GetProgram(
const String& rName)
925 if (mpPrograms.empty())
927 std::list<AkaiDirEntry> dummy;
931 std::list<AkaiProgram*>::iterator it;
932 std::list<AkaiProgram*>::iterator end = mpPrograms.end();
933 for (it = mpPrograms.begin(); it != end; it++)
935 if (*it && rName == (*it)->GetDirEntry().mName)
944 uint AkaiVolume::ListSamples(std::list<AkaiDirEntry>& rSamples)
949 std::list<AkaiSample*>::iterator it;
950 std::list<AkaiSample*>::iterator end = mpSamples.end();
951 for (it = mpSamples.begin(); it != end; it++)
953 rSamples.push_back((*it)->GetDirEntry());
954 return (uint)rSamples.size();
957 AkaiSample* AkaiVolume::GetSample(uint Index)
961 if (mpSamples.empty())
963 std::list<AkaiDirEntry> dummy;
967 std::list<AkaiSample*>::iterator it;
968 std::list<AkaiSample*>::iterator end = mpSamples.end();
969 for (it = mpSamples.begin(); it != end; it++)
971 if (*it && i == Index)
981 AkaiSample* AkaiVolume::GetSample(
const String& rName)
983 if (mpSamples.empty())
985 std::list<AkaiDirEntry> dummy;
989 std::list<AkaiSample*>::iterator it;
990 std::list<AkaiSample*>::iterator end = mpSamples.end();
991 for (it = mpSamples.begin(); it != end; it++)
993 if (*it && rName == (*it)->GetDirEntry().mName)
1002 AkaiDirEntry AkaiVolume::GetDirEntry()
1007 bool AkaiVolume::IsEmpty()
1009 return ReadDir() == 0;
1021 AkaiPartition::~AkaiPartition()
1023 std::list<AkaiVolume*>::iterator it;
1024 std::list<AkaiVolume*>::iterator end = mpVolumes.end();
1025 for (it = mpVolumes.begin(); it != end; it++)
1030 uint AkaiPartition::ListVolumes(std::list<AkaiDirEntry>& rVolumes)
1034 if (mpVolumes.empty())
1036 for (i = 0; i < AKAI_MAX_DIR_ENTRIES; i++)
1038 AkaiDirEntry DirEntry;
1039 ReadDirEntry(mpDisk,
this, DirEntry, AKAI_ROOT_ENTRY_OFFSET, i);
1040 DirEntry.mIndex = i;
1041 if (DirEntry.mType == AKAI_TYPE_DIR_S1000 || DirEntry.mType == AKAI_TYPE_DIR_S3000)
1045 if (!pVolume->IsEmpty())
1047 mpVolumes.push_back(pVolume);
1048 rVolumes.push_back(DirEntry);
1057 std::list<AkaiVolume*>::iterator it;
1058 std::list<AkaiVolume*>::iterator end = mpVolumes.end();
1059 for (it = mpVolumes.begin(); it != end; it++)
1061 rVolumes.push_back((*it)->GetDirEntry());
1063 return (uint)rVolumes.size();
1066 AkaiVolume* AkaiPartition::GetVolume(uint Index)
1070 if (mpVolumes.empty())
1072 std::list<AkaiDirEntry> dummy;
1076 std::list<AkaiVolume*>::iterator it;
1077 std::list<AkaiVolume*>::iterator end = mpVolumes.end();
1078 for (it = mpVolumes.begin(); it != end; it++)
1080 if (*it && i == Index)
1090 AkaiVolume* AkaiPartition::GetVolume(
const String& rName)
1092 if (mpVolumes.empty())
1094 std::list<AkaiDirEntry> dummy;
1098 std::list<AkaiVolume*>::iterator it;
1099 std::list<AkaiVolume*>::iterator end = mpVolumes.end();
1100 for (it = mpVolumes.begin(); it != end; it++)
1102 if (*it && rName == (*it)->GetDirEntry().mName)
1111 bool AkaiPartition::IsEmpty()
1113 std::list<AkaiDirEntry> Volumes;
1114 return ListVolumes(Volumes) == 0;
1125 AkaiDisk::~AkaiDisk()
1127 std::list<AkaiPartition*>::iterator it;
1128 std::list<AkaiPartition*>::iterator end = mpPartitions.end();
1129 for (it = mpPartitions.begin(); it != end ; it++)
1134 uint AkaiDisk::GetPartitionCount()
1136 if (!mpPartitions.empty())
1137 return (uint)mpPartitions.size();
1141 while (size != AKAI_PARTITION_END_MARK && size != 0x0fff && size != 0xffff
1142 && size<30720 && mpPartitions.size()<9)
1146 pPartition->Acquire();
1147 pPartition->SetOffset(offset);
1149 if (!pPartition->IsEmpty())
1151 mpPartitions.push_back(pPartition);
1154 mpDisk->SetPos(offset);
1155 if (!mpDisk->ReadInt16(&size))
1156 return (uint)mpPartitions.size();
1158 offset += AKAI_BLOCK_SIZE * t;
1162 return (uint)mpPartitions.size();
1167 std::list<AkaiPartition*>::iterator it;
1168 std::list<AkaiPartition*>::iterator end = mpPartitions.end();
1170 for (i = 0, it = mpPartitions.begin(); it != end && i != count; i++) it++;
1172 if (i != count || it == end)
1185 pDisk->SetPos(pPartition->GetOffset()+AKAI_FAT_OFFSET + block*2);
1186 pDisk->
Read(&value, 2,1);
1191 bool AkaiDiskElement::ReadDirEntry(
DiskImage* pDisk,
AkaiPartition* pPartition, AkaiDirEntry& rEntry,
int block,
int pos)
1195 if (block == AKAI_ROOT_ENTRY_OFFSET)
1197 pDisk->SetPos(pPartition->GetOffset()+AKAI_DIR_ENTRY_OFFSET + pos * AKAI_DIR_ENTRY_SIZE);
1198 pDisk->
Read(buffer, 12, 1);
1199 AkaiToAscii(buffer, 12);
1200 rEntry.mName = buffer;
1202 pDisk->ReadInt16(&rEntry.mType);
1203 pDisk->ReadInt16(&rEntry.mStart);
1211 pDisk->SetPos(block * AKAI_BLOCK_SIZE + pos * AKAI_FILE_ENTRY_SIZE + pPartition->GetOffset());
1216 temp = ReadFAT(pDisk, pPartition, block);
1217 pDisk->SetPos(pPartition->GetOffset()+temp * AKAI_BLOCK_SIZE + (pos - 341) * AKAI_FILE_ENTRY_SIZE);
1220 pDisk->
Read(buffer, 12, 1);
1221 AkaiToAscii(buffer, 12);
1222 rEntry.mName = buffer;
1225 pDisk->SetPos(4,akai_stream_curpos);
1226 pDisk->
Read(&t1, 1,1);
1229 pDisk->
Read(&t1, 1,1);
1230 pDisk->
Read(&t2, 1,1);
1231 pDisk->
Read(&t3, 1,1);
1232 rEntry.mSize = (
unsigned char)t1 | ((
unsigned char)t2 <<8) | ((
unsigned char)t3<<16);
1234 pDisk->ReadInt16(&rEntry.mStart,1);
1239 void AkaiDiskElement::AkaiToAscii(
char * buffer,
int length)
1243 for (i = 0; i < length; i++)
1245 if (buffer[i]>=0 && buffer[i]<=9)
1247 else if (buffer[i]==10)
1249 else if (buffer[i]>=11 && buffer[i]<=36)
1250 buffer[i] = 64+(buffer[i]-10);
1254 buffer[length] =
'\0';
1255 while (length-- > 0 && buffer[length] == 32)
1259 buffer[length+1] =
'\0';
1273 kern_return_t FindEjectableCDMedia( io_iterator_t *mediaIterator )
1275 kern_return_t kernResult;
1276 mach_port_t masterPort;
1277 CFMutableDictionaryRef classesToMatch;
1279 kernResult = IOMasterPort( MACH_PORT_NULL, &masterPort );
1280 if ( KERN_SUCCESS != kernResult )
1282 printf(
"IOMasterPort returned %d\n", kernResult );
1285 classesToMatch = IOServiceMatching( kIOCDMediaClass );
1286 if ( classesToMatch == NULL )
1288 printf(
"IOServiceMatching returned a NULL dictionary.\n" );
1292 CFDictionarySetValue( classesToMatch, CFSTR( kIOMediaEjectableKey ), kCFBooleanTrue );
1295 kernResult = IOServiceGetMatchingServices( masterPort, classesToMatch, mediaIterator );
1296 if ( KERN_SUCCESS != kernResult )
1298 printf(
"IOServiceGetMatchingServices returned %d\n", kernResult );
1304 kern_return_t GetBSDPath( io_iterator_t mediaIterator,
char *bsdPath, CFIndex maxPathSize )
1306 io_object_t nextMedia;
1307 kern_return_t kernResult = KERN_FAILURE;
1311 nextMedia = IOIteratorNext( mediaIterator );
1314 CFTypeRef bsdPathAsCFString;
1316 bsdPathAsCFString = IORegistryEntryCreateCFProperty( nextMedia,
1317 CFSTR( kIOBSDNameKey ),
1318 kCFAllocatorDefault,
1320 if ( bsdPathAsCFString )
1322 size_t devPathLength;
1324 strcpy( bsdPath, _PATH_DEV );
1325 strcat( bsdPath,
"r" );
1327 devPathLength = strlen( bsdPath );
1329 if ( CFStringGetCString( (__CFString*)bsdPathAsCFString,
1330 bsdPath + devPathLength,
1331 maxPathSize - devPathLength,
1332 kCFStringEncodingASCII ) )
1334 printf(
"BSD path: %s\n", bsdPath );
1335 kernResult = KERN_SUCCESS;
1338 CFRelease( bsdPathAsCFString );
1340 IOObjectRelease( nextMedia );
1354 #define MSF_TO_LBA(msf) (((((msf).minute * 60UL) + (msf).second) * 75UL) + (msf).frame - 150)
1362 struct _CDMSF address;
1370 u_char first_session;
1371 u_char last_session;
1372 struct _CDTOC_Desc trackdesc[1];
1375 static struct _CDTOC * ReadTOC (
const char * devpath )
1377 struct _CDTOC * toc_p = NULL;
1378 io_iterator_t iterator = 0;
1379 io_registry_entry_t service = 0;
1380 CFDictionaryRef properties = 0;
1382 mach_port_t port = 0;
1384 if (( devname = strrchr( devpath,
'/' )) != NULL )
1390 devname = (
char *) devpath;
1393 if ( IOMasterPort(bootstrap_port, &port ) != KERN_SUCCESS )
1395 printf(
"IOMasterPort failed\n" );
goto Exit ;
1397 if ( IOServiceGetMatchingServices( port, IOBSDNameMatching( port, 0, devname ),
1398 &iterator ) != KERN_SUCCESS )
1400 printf(
"IOServiceGetMatchingServices failed\n" );
goto Exit ;
1404 IOObjectGetClass(iterator,buffer);
1405 printf(
"Service: %s\n",buffer);
1408 IOIteratorReset (iterator);
1409 service = IOIteratorNext( iterator );
1411 IOObjectRelease( iterator );
1414 while ( service && !IOObjectConformsTo( service,
"IOCDMedia" ))
1417 IOObjectGetClass(service,buffer);
1418 printf(
"Service: %s\n",buffer);
1420 if ( IORegistryEntryGetParentIterator( service, kIOServicePlane, &iterator ) != KERN_SUCCESS )
1422 printf(
"IORegistryEntryGetParentIterator failed\n" );
1426 IOObjectRelease( service );
1427 service = IOIteratorNext( iterator );
1428 IOObjectRelease( iterator );
1431 if ( service == NULL )
1433 printf(
"CD media not found\n" );
goto Exit ;
1435 if ( IORegistryEntryCreateCFProperties( service, (__CFDictionary **) &properties,
1436 kCFAllocatorDefault,
1437 kNilOptions ) != KERN_SUCCESS )
1439 printf(
"IORegistryEntryGetParentIterator failed\n" );
goto Exit ;
1442 data = (CFDataRef) CFDictionaryGetValue( properties, CFSTR(
"TOC" ) );
1445 printf(
"CFDictionaryGetValue failed\n" );
goto Exit ;
1453 buflen = CFDataGetLength( data ) + 1;
1454 range = CFRangeMake( 0, buflen );
1455 toc_p = (
struct _CDTOC *) malloc( buflen );
1456 if ( toc_p == NULL )
1458 printf(
"Out of memory\n" );
goto Exit ;
1462 CFDataGetBytes( data, range, (
unsigned char *) toc_p );
1470 CFRelease( properties );
1476 IOObjectRelease( service );
1488 sprintf(buffer,
"%c:\\",
'A'+disk);
1489 mSize = GetFileSize(buffer,NULL);
1491 sprintf(buffer,
"\\\\.\\%c:",
'a'+disk);
1492 mFile = CreateFile(buffer, GENERIC_READ,0,NULL,OPEN_EXISTING, FILE_FLAG_RANDOM_ACCESS,NULL);
1496 DISK_GEOMETRY* pdg = &dg;
1497 BOOL res = DeviceIoControl(mFile,
1498 IOCTL_DISK_GET_DRIVE_GEOMETRY,
1506 mSize = dg.BytesPerSector * dg.SectorsPerTrack * dg.TracksPerCylinder * dg.Cylinders.LowPart;
1507 mClusterSize = dg.BytesPerSector;
1509 #elif defined(_CARBON_) || defined(__APPLE__)
1510 kern_return_t kernResult;
1511 io_iterator_t mediaIterator;
1512 char bsdPath[ MAXPATHLEN ];
1513 kernResult = FindEjectableCDMedia( &mediaIterator );
1514 kernResult = GetBSDPath( mediaIterator, bsdPath,
sizeof( bsdPath ) );
1515 if ( bsdPath[ 0 ] !=
'\0' )
1517 strcpy(bsdPath,
"/dev/rdisk1s0");
1519 struct _CDTOC * toc = ReadTOC( bsdPath );
1522 size_t toc_entries = ( toc->length - 2 ) /
sizeof (
struct _CDTOC_Desc );
1524 int start_sector = -1;
1525 int data_track = -1;
1530 for (ssize_t i=toc_entries - 1; i>=0; i-- )
1532 if ( start_sector != -1 )
1534 start_sector = MSF_TO_LBA(toc->trackdesc[i].p) - start_sector;
1538 if (( toc->trackdesc[i].ctrl_adr >> 4) != 1 )
1540 if ( toc->trackdesc[i].ctrl_adr & 0x04 )
1542 data_track = toc->trackdesc[i].point;
1543 start_sector = MSF_TO_LBA(toc->trackdesc[i].p);
1548 if ( start_sector == -1 )
1557 mFile = open(bsdPath,O_RDONLY);
1559 printf(
"Error while opening file: %s\n",bsdPath);
1562 printf(
"opened file: %s\n",bsdPath);
1564 mSize = (int) lseek(mFile,1000000000,SEEK_SET);
1565 printf(
"size %d\n",mSize);
1566 lseek(mFile,0,SEEK_SET);
1568 mSize = 700 * 1024 * 1024;
1572 if ( mediaIterator )
1574 IOObjectRelease( mediaIterator );
1577 OpenStream(
"/dev/cdrom");
1581 void DiskImage::Init()
1585 mCluster = (uint)-1;
1589 mpCache = (
char*) VirtualAlloc(NULL,mClusterSize,MEM_COMMIT,PAGE_READWRITE);
1595 DiskImage::~DiskImage()
1598 if (mFile != INVALID_HANDLE_VALUE)
1602 #elif defined _CARBON_ || defined(__APPLE__) || LINUX
1611 VirtualFree(mpCache, 0, MEM_RELEASE);
1612 #elif defined(_CARBON_) || defined(__APPLE__) || LINUX
1618 akai_stream_state_t DiskImage::GetState()
const
1620 if (!mFile)
return akai_stream_closed;
1621 if (mPos > mSize)
return akai_stream_end_reached;
1622 return akai_stream_ready;
1625 int DiskImage::GetPos()
const
1630 int DiskImage::SetPos(
int Where, akai_stream_whence_t Whence)
1636 case akai_stream_start:
1641 case akai_stream_curpos:
1644 case akai_stream_end:
1655 int DiskImage::Available (uint WordSize)
1657 return (mSize-mPos)/WordSize;
1663 int sizetoread = WordCount * WordSize;
1665 while (sizetoread > 0) {
1666 if (mSize <= mPos)
return readbytes / WordSize;
1667 int requestedCluster = (mRegularFile) ? mPos / mClusterSize
1668 : mPos / mClusterSize + mStartFrame;
1669 if (mCluster != requestedCluster) {
1670 mCluster = requestedCluster;
1672 if (mCluster * mClusterSize != SetFilePointer(mFile, mCluster * mClusterSize, NULL, FILE_BEGIN)) {
1673 printf(
"ERROR: couldn't seek device!\n");
1675 if ((readbytes > 0) && (mEndian != eEndianNative)) {
1677 case 2: bswap_16_s ((uint16*)pData, readbytes);
break;
1678 case 4: bswap_32_s ((uint32*)pData, readbytes);
break;
1679 case 8: bswap_64_s ((uint64*)pData, readbytes);
break;
1683 return readbytes / WordSize;
1686 ReadFile(mFile, mpCache, mClusterSize, &size, NULL);
1687 #elif defined(_CARBON_) || defined(__APPLE__) || LINUX
1688 if (mCluster * mClusterSize != lseek(mFile, mCluster * mClusterSize, SEEK_SET))
1689 return readbytes / WordSize;
1691 read(mFile, mpCache, mClusterSize);
1697 int currentReadSize = sizetoread;
1698 int posInCluster = mPos % mClusterSize;
1699 if (currentReadSize > mClusterSize - posInCluster)
1700 currentReadSize = mClusterSize - posInCluster;
1702 memcpy((uint8_t*)pData + readbytes, mpCache + posInCluster, currentReadSize);
1704 mPos += currentReadSize;
1705 readbytes += currentReadSize;
1706 sizetoread -= currentReadSize;
1711 if ((readbytes > 0) && (mEndian != eEndianNative))
1714 case 2: bswap_16_s ((uint16_t*)pData, readbytes);
break;
1715 case 4: bswap_32_s ((uint32_t*)pData, readbytes);
break;
1716 case 8: bswap_64_s ((uint64_t*)pData, readbytes);
break;
1720 return readbytes / WordSize;
1723 void DiskImage::ReadInt8(uint8_t* pData, uint WordCount) {
1724 Read(pData, WordCount, 1);
1727 void DiskImage::ReadInt16(uint16_t* pData, uint WordCount) {
1729 for (i = 0; i < WordCount; i++) {
1730 *(pData + i) = ReadInt16();
1734 void DiskImage::ReadInt32(uint32_t* pData, uint WordCount) {
1736 for (i = 0; i < WordCount; i++) {
1737 *(pData + i) = ReadInt32();
1741 int DiskImage::ReadInt8(uint8_t* pData) {
1742 return Read(pData, 1, 1);
1745 int DiskImage::ReadInt16(uint16_t* pData) {
1746 int result =
Read(pData, 1, 2);
1748 swapBytes_16(pData);
1753 int DiskImage::ReadInt32(uint32_t* pData) {
1754 int result =
Read(pData, 1, 4);
1756 swapBytes_32(pData);
1761 uint8_t DiskImage::ReadInt8()
1768 uint16_t DiskImage::ReadInt16()
1773 swapBytes_16(&word);
1778 uint32_t DiskImage::ReadInt32()
1783 swapBytes_32(&word);
1788 void DiskImage::OpenStream(
const char* path) {
1790 mFile = CreateFile(path, GENERIC_READ,0,NULL,OPEN_EXISTING, FILE_FLAG_RANDOM_ACCESS,NULL);
1791 BY_HANDLE_FILE_INFORMATION FileInfo;
1792 GetFileInformationByHandle(mFile,&FileInfo);
1793 mSize = FileInfo.nFileSizeLow;
1794 #elif defined(_CARBON_) || defined(__APPLE__) || LINUX
1795 struct stat filestat;
1796 stat(path,&filestat);
1797 mFile = open(path, O_RDONLY | O_NONBLOCK);
1799 printf(
"Can't open %s\n", path);
1804 if (S_ISREG(filestat.st_mode)) {
1805 printf(
"Using regular Akai image file.\n");
1806 mRegularFile =
true;
1807 mSize = (int) filestat.st_size;
1808 mClusterSize = DISK_CLUSTER_SIZE;
1809 mpCache = (
char*) malloc(mClusterSize);
1811 #if defined(_CARBON_) || defined(__APPLE__)
1812 printf(
"Can't open %s: not a regular file\n", path);
1814 mRegularFile =
false;
1815 mClusterSize = CD_FRAMESIZE;
1816 mpCache = (
char*) malloc(mClusterSize);
1818 struct cdrom_tochdr tochdr;
1819 struct cdrom_tocentry tocentry;
1821 if (ioctl(mFile, CDROMREADTOCHDR, (
unsigned long)&tochdr) < 0) {
1822 printf(
"Trying to read TOC of %s failed\n", path);
1827 printf(
"Total tracks: %d\n", tochdr.cdth_trk1);
1830 tocentry.cdte_format = CDROM_LBA;
1832 int firstDataTrack = -1;
1833 int start, end, length;
1836 for (
int t = tochdr.cdth_trk1; t >= 0; t--) {
1837 tocentry.cdte_track = (t == tochdr.cdth_trk1) ? CDROM_LEADOUT : t + 1;
1838 if (ioctl(mFile, CDROMREADTOCENTRY, (
unsigned long)&tocentry) < 0){
1839 printf(
"Failed to read TOC entry for track %d\n", tocentry.cdte_track);
1844 if (tocentry.cdte_track == CDROM_LEADOUT) {
1845 printf(
"Lead Out: Start(LBA)=%d\n", tocentry.cdte_addr.lba);
1848 printf(
"Track %d: Start(LBA)=%d End(LBA)=%d Length(Blocks)=%d ",
1849 tocentry.cdte_track, tocentry.cdte_addr.lba, prev_addr - 1, prev_addr - tocentry.cdte_addr.lba);
1850 if (tocentry.cdte_ctrl & CDROM_DATA_TRACK) {
1851 printf(
"Type: Data\n");
1852 firstDataTrack = tocentry.cdte_track;
1853 start = tocentry.cdte_addr.lba;
1854 end = prev_addr - 1;
1855 length = prev_addr - tocentry.cdte_addr.lba;
1857 else printf(
"Type: Audio\n");
1859 prev_addr = tocentry.cdte_addr.lba;
1862 if (firstDataTrack == -1) {
1863 printf(
"Sorry, no data track found on %s\n", path);
1869 printf(
"Ok, I'll pick track %d\n", firstDataTrack);
1870 mStartFrame = start;
1872 mSize = length * CD_FRAMESIZE;
1880 #if defined(_CARBON_) || defined(__APPLE__) || LINUX
1881 const uint bufferSize = 524288;
1882 int fOut = open(path, O_WRONLY | O_NONBLOCK | O_CREAT | O_TRUNC,
1883 S_IRUSR | S_IWUSR | S_IRGRP);
1885 printf(
"Can't open output file %s\n", path);
1888 uint8_t* pBuffer =
new uint8_t[bufferSize];
1890 while (Available() > 0) {
1891 int readBytes =
Read(pBuffer,bufferSize,1);
1892 if (readBytes > 0) write(fOut,pBuffer,readBytes);
1901 inline void DiskImage::swapBytes_16(
void* Word) {
1903 byteCache = *((uint8_t*) Word);
1904 *((uint8_t*) Word) = *((uint8_t*) Word + 1);
1905 *((uint8_t*) Word + 1) = byteCache;
1908 inline void DiskImage::swapBytes_32(
void* Word) {
1910 byteCache = *((uint8_t*) Word);
1911 *((uint8_t*) Word) = *((uint8_t*) Word + 3);
1912 *((uint8_t*) Word + 3) = byteCache;
1913 byteCache = *((uint8_t*) Word + 1);
1914 *((uint8_t*) Word + 1) = *((uint8_t*) Word + 2);
1915 *((uint8_t*) Word + 2) = byteCache;
Toplevel AKAI image interpreter.
Encapsulates one disk partition of an AKAI disk.
AKAI instrument definition.
Subdivision of an AKAI disk partition.
Accessing AKAI image either from file or a drive (i.e.
bool WriteImage(const char *path)
Extract Akai data track and write it into a regular file.
virtual int Read(void *pData, uint WordCount, uint WordSize)
Returns number of successfully read words.
DiskImage(const char *path)
Open an image from a file.