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

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

Properties

Name Value
svn:executable *

  ViewVC Help
Powered by ViewVC