/[svn]/libgig/trunk/src/tools/akaiextract.cpp
ViewVC logotype

Contents of /libgig/trunk/src/tools/akaiextract.cpp

Parent Directory Parent Directory | Revision Log Revision Log


Revision 3983 - (show annotations) (download)
Tue Aug 3 16:05:32 2021 UTC (2 years, 7 months ago) by schoenebeck
File size: 20967 byte(s)
Drop "svn:executable" property from all source files.

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-2015
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 // akaiextract.cpp : Defines the entry point for the console application.
22 //
23
24 #ifdef HAVE_CONFIG_H
25 #include <config.h>
26 #endif
27
28 #ifdef WIN32
29 # define _WIN32_WINNT 0x0500
30 # include <windows.h>
31 # include <conio.h>
32 #else
33 # include <errno.h>
34 # include <dlfcn.h>
35 #endif
36
37 #include <unistd.h>
38 #include <dirent.h>
39 #include <sys/stat.h>
40 #include <sys/types.h>
41
42 // for testing the disk streaming methods
43 #define USE_DISK_STREAMING 1
44
45 #include <stdio.h>
46 #include <stdlib.h>
47 #include <iostream>
48 #include <sstream>
49 #include <string.h>
50
51 #include "../Akai.h"
52
53 // only libsndfile is available for Windows, so we use that for writing the sound files
54 #ifdef WIN32
55 # define HAVE_SNDFILE 1
56 #endif // WIN32
57
58 // abort compilation here if neither libsndfile nor libaudiofile are available
59 #if !HAVE_SNDFILE && !HAVE_AUDIOFILE
60 # error "Neither libsndfile nor libaudiofile seem to be available!"
61 # error "(HAVE_SNDFILE and HAVE_AUDIOFILE are both false)"
62 #endif
63
64 // we prefer libsndfile before libaudiofile
65 #if HAVE_SNDFILE
66 # include <sndfile.h>
67 #else
68 # include <audiofile.h>
69 #endif // HAVE_SNDFILE
70
71 #if !HAVE_SNDFILE // use libaudiofile
72 void* hAFlib; // handle to libaudiofile
73 void openAFlib(void);
74 void closeAFlib(void);
75 // pointers to libaudiofile functions
76 AFfilesetup(*_afNewFileSetup)(void);
77 void(*_afFreeFileSetup)(AFfilesetup);
78 void(*_afInitChannels)(AFfilesetup,int,int);
79 void(*_afInitSampleFormat)(AFfilesetup,int,int,int);
80 void(*_afInitFileFormat)(AFfilesetup,int);
81 void(*_afInitRate)(AFfilesetup,int,double);
82 int(*_afWriteFrames)(AFfilehandle,int,const void*,int);
83 AFfilehandle(*_afOpenFile)(const char*,const char*,AFfilesetup);
84 int(*_afCloseFile)(AFfilehandle file);
85 #endif // !HAVE_SNDFILE
86
87 int writeWav(AkaiSample* sample, const char* filename, void* samples, long samplecount, int channels = 1, int bitdepth = 16, long rate = 44100);
88 void ConvertAkaiToAscii(char * buffer, int length); // debugging purpose only
89
90 using namespace std;
91
92 template<class T> inline std::string ToString(T o) {
93 std::stringstream ss;
94 ss << o;
95 return ss.str();
96 }
97
98 void PrintLastError(char* file, int line)
99 {
100 #ifdef WIN32
101 LPVOID lpMsgBuf;
102 FormatMessage(
103 FORMAT_MESSAGE_ALLOCATE_BUFFER |
104 FORMAT_MESSAGE_FROM_SYSTEM |
105 FORMAT_MESSAGE_IGNORE_INSERTS,
106 NULL,
107 GetLastError(),
108 MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language
109 (LPTSTR) &lpMsgBuf,
110 0,
111 NULL
112 );
113 // Display the string.
114 char buf[2048];
115 sprintf(buf,"%s(%d): %s",file, line, (LPCTSTR)lpMsgBuf);
116 printf("%s",buf);
117 OutputDebugString(buf);
118 // Free the buffer.
119 LocalFree( lpMsgBuf );
120 #endif
121 }
122
123 #define SHOWERROR PrintLastError(__FILE__,__LINE__)
124
125 static void printUsage() {
126 #ifdef WIN32
127 const wchar_t* msg =
128 L"akaiextract <source-drive-letter>: <destination-dir>\n"
129 "by S\351bastien M\351trot (meeloo@meeloo.net)\n\n"
130 "Reads an AKAI media (i.e. CDROM, ZIP disk) and extracts all its audio\n"
131 "samples as .wav files to the given output directory. If the given output\n"
132 "directory does not exist yet, then it will be created.\n\n"
133 "Available types of your drives:\n";
134 DWORD n = wcslen(msg);
135 WriteConsoleW(GetStdHandle(STD_OUTPUT_HANDLE), msg, n, &n, NULL);
136 char rootpath[4]="a:\\";
137 for (char drive ='a'; drive <= 'z'; drive++) {
138 rootpath[0] = drive;
139 int type = GetDriveType(rootpath);
140 if (type != DRIVE_NO_ROOT_DIR) {
141 printf("Drive %s is a ", rootpath);
142 switch(type) {
143 case DRIVE_UNKNOWN: printf("Unknown\n"); break;
144 case DRIVE_NO_ROOT_DIR: printf("Unavailable\n");
145 case DRIVE_REMOVABLE: printf("removable disk\n"); break;
146 case DRIVE_FIXED: printf("fixed disk\n"); break;
147 case DRIVE_REMOTE: printf("remote (network) drive\n"); break;
148 case DRIVE_CDROM: printf("CD-ROM drive\n"); break;
149 case DRIVE_RAMDISK: printf("RAM disk\n"); break;
150 }
151 }
152 }
153 printf("\n");
154 #elif defined _CARBON_
155 setlocale(LC_CTYPE, "");
156 printf("%ls",
157 L"akaiextract [<source-path>] <destination-dir>\n"
158 "by S\351bastien M\351trot (meeloo@meeloo.net)\n\n"
159 "Reads an AKAI media (i.e. CDROM, ZIP disk) and extracts all its audio\n"
160 "samples as .wav files to the given output directory. If the given output\n"
161 "directory does not exist yet, then it will be created.\n\n"
162 "<source-path> - path of the source AKAI image file, if omitted CDROM\n"
163 " drive ('/dev/rdisk1s0') will be accessed\n\n"
164 "<destination-dir> - target directory where samples will be written to\n\n"
165 );
166 #else
167 setlocale(LC_CTYPE, "");
168 printf("%ls",
169 L"akaiextract <source-path> <destination-dir>\n"
170 "by S\351bastien M\351trot (meeloo@meeloo.net)\n"
171 "Linux port by Christian Schoenebeck\n\n"
172 "Reads an AKAI media (i.e. CDROM, ZIP disk) and extracts all its audio\n"
173 "samples as .wav files to the given output directory. If the given output\n"
174 "directory does not exist yet, then it will be created.\n\n"
175 "<source-path> - path of the source drive or image file (i.e. /dev/cdrom)\n\n"
176 "<destination-dir> - target directory where samples will be written to\n\n"
177 );
178 #endif
179 }
180
181 int main(int argc, char** argv) {
182 #if defined _CARBON_
183 if (argc < 2) {
184 printUsage();
185 return -1;
186 }
187 #else
188 if (argc < 3) {
189 printUsage();
190 return -1;
191 }
192 #endif
193
194 // open input source
195 DiskImage* pImage = NULL;
196 #ifdef WIN32
197 char drive = toupper(*(argv[1]))-'A';
198 printf("opening drive %c:\n",drive+'a');
199 pImage = new DiskImage(drive);
200 #elif defined _CARBON_
201 if (argc == 2) {
202 printf("Opening AKAI media at '/dev/rdisk1s0'\n");
203 pImage = new DiskImage((int)0); // arbitrary int, argument will be ignored
204 } else {
205 printf("Opening source AKAI image file at '%s'\n", argv[1]);
206 pImage = new DiskImage(argv[1]);
207 }
208 #else
209 printf("Opening AKAI media or image file at '%s'\n", argv[1]);
210 pImage = new DiskImage(argv[1]);
211 #endif
212
213 // determine output directory path
214 #if defined _CARBON_
215 const char* outPath = (argc == 2) ? argv[1] : argv[2];
216 #else
217 const char* outPath = argv[2];
218 #endif
219
220 AkaiDisk* pAkai = new AkaiDisk(pImage);
221
222 printf("Reading Akai file entries (this may take a while)...\n");
223 printf("Partitions: %d\n", pAkai->GetPartitionCount());
224 printf("Partitions list:\n");
225 long totalSamplesSize = 0, totalSamples = 0;
226 uint i;
227 for (i = 0; i < pAkai->GetPartitionCount(); i++)
228 {
229 printf("%2.2d: Partition %c\n",i,'A'+i);
230 AkaiPartition* pPartition = pAkai->GetPartition(i);
231 if (pPartition)
232 {
233 std::list<AkaiDirEntry> Volumes;
234 pPartition->ListVolumes(Volumes);
235 std::list<AkaiDirEntry>::iterator it;
236 std::list<AkaiDirEntry>::iterator end = Volumes.end();
237 int vol = 0;
238 for (it = Volumes.begin(); it != end; it++)
239 {
240 AkaiDirEntry DirEntry = *it;
241 printf(" %d (%d) '%.12s' [start=%d - type=%d]\n", vol,DirEntry.mIndex, DirEntry.mName.c_str(), DirEntry.mStart, DirEntry.mType);
242 AkaiVolume* pVolume = pPartition->GetVolume(vol);
243 if (pVolume)
244 {
245 std::list<AkaiDirEntry> Programs;
246 pVolume->ListPrograms(Programs);
247 std::list<AkaiDirEntry>::iterator it;
248 std::list<AkaiDirEntry>::iterator end = Programs.end();
249
250 uint prog = 0;
251 for (it = Programs.begin(); it != end; it++)
252 {
253 AkaiDirEntry DirEntry = *it;
254 printf(" Program %d (%d) '%.12s' [start=%d size=%d - type=%c]\n", prog,DirEntry.mIndex, DirEntry.mName.c_str(), DirEntry.mStart, DirEntry.mSize, DirEntry.mType);
255 AkaiProgram* pProgram = pVolume->GetProgram(prog);
256 printf(" Number of key groups: %d\n",pProgram->mNumberOfKeygroups);
257 pProgram->Release();
258 prog++;
259 }
260
261 std::list<AkaiDirEntry> Samples;
262 pVolume->ListSamples(Samples);
263 end = Samples.end();
264
265 uint samp = 0;
266 for (it = Samples.begin(); it != end; it++)
267 {
268 AkaiDirEntry DirEntry = *it;
269 printf(" Sample %d (%d) '%.12s' [start=%d size=%d - type=%c]\n", samp,DirEntry.mIndex, DirEntry.mName.c_str(), DirEntry.mStart, DirEntry.mSize, DirEntry.mType);
270 AkaiSample* pSample= pVolume->GetSample(samp);
271 printf(" Number of samples: %d (%d Hz)\n",pSample->mNumberOfSamples,pSample->mSamplingFrequency);
272 totalSamplesSize += pSample->mNumberOfSamples;
273 totalSamples++;
274 pSample->Release();
275 samp++;
276 }
277
278 pVolume->Release();
279 }
280
281 vol++;
282 }
283
284 pPartition->Release();
285 }
286 }
287
288 #if 0
289 printf("Writing Akai track to hard disk...");
290 fflush(stdout);
291 bool success = pImage->WriteImage("/tmp/some.akai");
292 if (success) printf("ok\n");
293 else printf("error\n");
294 #endif
295
296 #if !HAVE_SNDFILE // use libaudiofile
297 hAFlib = NULL;
298 openAFlib();
299 #endif // !HAVE_SNDFILE
300
301 totalSamplesSize *= 2; // due to 16 bit samples
302 printf("There are %ld samples on this disk with a total size of %ld Bytes. ",
303 totalSamples, totalSamplesSize);
304 printf("Do you want to extract them (.wav files will be written to '%s')? [y/n]\n", outPath);
305 char c = getchar();
306 if (c == 'y' || c == 'Y') {
307 bool errorOccured = false;
308 DIR* dir = opendir(outPath);
309 if (!dir) {
310 if (errno == ENOENT) {
311 struct stat filestat;
312 #ifdef WIN32
313 if (stat(outPath, &filestat) < 0) {
314 #else
315 if (lstat(outPath, &filestat) < 0) {
316 #endif
317 printf("Creating output directory '%s'...", outPath);
318 fflush(stdout);
319 #ifdef WIN32
320 if (mkdir(outPath) < 0) {
321 #else
322 if (mkdir(outPath, 0770) < 0) {
323 #endif
324 perror("failed");
325 errorOccured = true;
326 }
327 else printf("ok\n");
328 }
329 else {
330 #if !defined(WIN32)
331 if (!S_ISLNK(filestat.st_mode)) {
332 #endif
333 printf("Cannot create output directory '%s': ", outPath);
334 printf("a file of that name already exists\n");
335 errorOccured = true;
336 #if !defined(WIN32)
337 }
338 #endif
339 }
340 }
341 else {
342 perror("error while opening output directory");
343 errorOccured = true;
344 }
345 }
346 if (dir) closedir(dir);
347 if (!errorOccured) {
348 printf("Starting extraction...\n");
349 long currentsample = 1;
350 uint i;
351 for (i = 0; i < pAkai->GetPartitionCount() && !errorOccured; i++) {
352 AkaiPartition* pPartition = pAkai->GetPartition(i);
353 if (pPartition) {
354 std::list<AkaiDirEntry> Volumes;
355 pPartition->ListVolumes(Volumes);
356 std::list<AkaiDirEntry>::iterator it;
357 std::list<AkaiDirEntry>::iterator end = Volumes.end();
358 int vol = 0;
359 for (it = Volumes.begin(); it != end && !errorOccured; it++) {
360 AkaiDirEntry DirEntry = *it;
361 AkaiVolume* pVolume = pPartition->GetVolume(vol);
362 if (pVolume) {
363 std::list<AkaiDirEntry> Samples;
364 pVolume->ListSamples(Samples);
365 std::list<AkaiDirEntry>::iterator it;
366 std::list<AkaiDirEntry>::iterator end = Samples.end();
367 uint samp = 0;
368 for (it = Samples.begin(); it != end && !errorOccured; it++) {
369 AkaiDirEntry DirEntry = *it;
370 AkaiSample* pSample = pVolume->GetSample(samp);
371 printf("Extracting Sample (%ld/%ld) %s...",
372 currentsample++,
373 totalSamples,
374 DirEntry.mName.c_str());
375 fflush(stdout);
376 #if USE_DISK_STREAMING
377 if (pSample->LoadHeader()) {
378 uint16_t* pSampleBuf = new uint16_t[pSample->mNumberOfSamples];
379 pSample->Read(pSampleBuf, pSample->mNumberOfSamples);
380
381 String filename = outPath + String("/") + DirEntry.mName + ".wav";
382 int res = writeWav(pSample,
383 filename.c_str(),
384 pSampleBuf,
385 pSample->mNumberOfSamples);
386 if (res < 0) {
387 printf("couldn't write sample data\n");
388 errorOccured = true;
389 }
390 else printf("ok\n");
391 delete[] pSampleBuf;
392 }
393 else {
394 printf("failed to load sample data\n");
395 errorOccured = true;
396 }
397 #else // no disk streaming
398 if (pSample->LoadSampleData()) {
399
400 String filename = outPath + String("/") + DirEntry.mName + ".wav";
401 int res = writeWav(pSample,
402 filename.c_str(),
403 pSample->mpSamples,
404 pSample->mNumberOfSamples);
405 if (res < 0) {
406 printf("couldn't write sample data\n");
407 errorOccured = true;
408 }
409 else printf("ok\n");
410 pSample->ReleaseSampleData();
411 }
412 else {
413 printf("failed to load sample data\n");
414 errorOccured = true;
415 }
416 #endif // USE_DISK_STREAMING
417 pSample->Release();
418 samp++;
419 }
420 pVolume->Release();
421 }
422 vol++;
423 }
424 pPartition->Release();
425 }
426 }
427 }
428 if (errorOccured) printf("Extraction failed\n");
429 }
430
431 #if !HAVE_SNDFILE // use libaudiofile
432 closeAFlib();
433 #endif // !HAVE_SNDFILE
434
435 #if 0
436 // this is just for debugging purpose - it converts the whole image to ascii
437 printf("Converting...\n");
438 FILE* f = fopen("akai_converted_to_ascii.iso", "w");
439 if (f) {
440 char* buf = (char*) malloc(AKAI_BLOCK_SIZE);
441 pImage->SetPos(0);
442 while (pImage->Available(1)) {
443 int readbytes = pImage->Read(buf,1,AKAI_BLOCK_SIZE);
444 if (readbytes != AKAI_BLOCK_SIZE) printf("Block incomplete (read: %d)\n",readbytes);
445 ConvertAkaiToAscii(buf, readbytes);
446 fwrite(buf, AKAI_BLOCK_SIZE, 1, f);
447 }
448 free(buf);
449 fclose(f);
450 }
451 else printf("Could not open file\n");
452 #endif
453
454 delete pAkai;
455 delete pImage;
456 #if WIN32
457 while(!_kbhit());
458 #endif
459 }
460
461 // only for debugging
462 void ConvertAkaiToAscii(char * buffer, int length)
463 {
464 int i;
465
466 for (i = 0; i < length; i++)
467 {
468 if (buffer[i]>=0 && buffer[i]<=9)
469 buffer[i] +=48;
470 else if (buffer[i]==10)
471 buffer[i] = 32;
472 else if (buffer[i]>=11 && buffer[i]<=36)
473 buffer[i] = 64+(buffer[i]-10);
474 else
475 buffer[i] = 32;
476 }
477 buffer[length] = '\0';
478 while (length-- > 0 && buffer[length] == 32)
479 {
480 // This block intentionaly left blank :)
481 }
482 buffer[length+1] = '\0';
483 }
484
485 int writeWav(AkaiSample* sample, const char* filename, void* samples, long samplecount, int channels, int bitdepth, long rate) {
486 #if HAVE_SNDFILE
487 SNDFILE* hfile;
488 SF_INFO sfinfo;
489 SF_INSTRUMENT instr;
490 int format = SF_FORMAT_WAV;
491 switch (bitdepth) {
492 case 8:
493 format |= SF_FORMAT_PCM_S8;
494 break;
495 case 16:
496 format |= SF_FORMAT_PCM_16;
497 break;
498 case 24:
499 format |= SF_FORMAT_PCM_24;
500 break;
501 case 32:
502 format |= SF_FORMAT_PCM_32;
503 break;
504 default:
505 cerr << "Error: Bithdepth " << ToString(bitdepth) << " not supported by libsndfile, ignoring sample!\n" << flush;
506 return -1;
507 }
508 memset(&sfinfo, 0, sizeof (sfinfo));
509 memset(&instr, 0, sizeof (instr));
510 sfinfo.samplerate = rate;
511 sfinfo.frames = samplecount;
512 sfinfo.channels = channels;
513 sfinfo.format = format;
514 if (!(hfile = sf_open(filename, SFM_WRITE, &sfinfo))) {
515 cerr << "Error: Unable to open output file \'" << filename << "\'.\n" << flush;
516 return -1;
517 }
518 instr.basenote = sample->mMidiRootNote;
519 instr.detune = sample->mTuneCents;
520 for (int i = 0; i < sample->mActiveLoops; ++i) {
521 instr.loop_count = sample->mActiveLoops;
522 instr.loops[i].mode = SF_LOOP_FORWARD;
523 instr.loops[i].start = sample->mLoops[i].mMarker;
524 instr.loops[i].end = sample->mLoops[i].mCoarseLength;
525 instr.loops[i].count = 0; // infinite
526 }
527 sf_command(hfile, SFC_SET_INSTRUMENT, &instr, sizeof(instr));
528 sf_count_t res = bitdepth == 24 ?
529 sf_write_int(hfile, static_cast<int*>(samples), channels * samplecount) :
530 sf_write_short(hfile, static_cast<short*>(samples), channels * samplecount);
531 if (res != channels * samplecount) {
532 cerr << sf_strerror(hfile) << endl << flush;
533 sf_close(hfile);
534 return -1;
535 }
536 sf_close(hfile);
537 #else // use libaudiofile
538 AFfilesetup setup = _afNewFileSetup();
539 _afInitFileFormat(setup, AF_FILE_WAVE);
540 _afInitChannels(setup, AF_DEFAULT_TRACK, channels);
541 _afInitSampleFormat(setup, AF_DEFAULT_TRACK, AF_SAMPFMT_TWOSCOMP, bitdepth);
542 _afInitRate(setup, AF_DEFAULT_TRACK, rate);
543 if (setup == AF_NULL_FILESETUP) return -1;
544 AFfilehandle hFile = _afOpenFile(filename, "w", setup);
545 if (hFile == AF_NULL_FILEHANDLE) return -1;
546 if (_afWriteFrames(hFile, AF_DEFAULT_TRACK, samples, samplecount) < 0) return -1;
547 _afCloseFile(hFile);
548 _afFreeFileSetup(setup);
549 #endif // HAVE_SNDFILE
550
551 return 0; // success
552 }
553
554 #if !HAVE_SNDFILE // use libaudiofile
555 void openAFlib() {
556 hAFlib = dlopen("libaudiofile.so", RTLD_NOW);
557 if (!hAFlib) {
558 cout << "Unable to load library libaudiofile.so: " << dlerror() << endl;
559 return;
560 }
561 _afNewFileSetup = (AFfilesetup(*)(void)) dlsym(hAFlib, "afNewFileSetup");
562 _afFreeFileSetup = (void(*)(AFfilesetup)) dlsym(hAFlib, "afFreeFileSetup");
563 _afInitChannels = (void(*)(AFfilesetup,int,int)) dlsym(hAFlib, "afInitChannels");
564 _afInitSampleFormat = (void(*)(AFfilesetup,int,int,int)) dlsym(hAFlib, "afInitSampleFormat");
565 _afInitFileFormat = (void(*)(AFfilesetup,int)) dlsym(hAFlib, "afInitFileFormat");
566 _afInitRate = (void(*)(AFfilesetup,int,double)) dlsym(hAFlib, "afInitRate");
567 _afWriteFrames = (int(*)(AFfilehandle,int,const void*,int)) dlsym(hAFlib, "afWriteFrames");
568 _afOpenFile = (AFfilehandle(*)(const char*,const char*,AFfilesetup)) dlsym(hAFlib, "afOpenFile");
569 _afCloseFile = (int(*)(AFfilehandle file)) dlsym(hAFlib, "afCloseFile");
570 if (dlerror()) cout << "Failed to load function from libaudiofile.so: " << dlerror() << endl;
571 }
572
573 void closeAFlib() {
574 if (hAFlib) dlclose(hAFlib);
575 }
576 #endif // !HAVE_SNDFILE

  ViewVC Help
Powered by ViewVC