/[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 2574 - (show annotations) (download)
Thu May 22 15:54:02 2014 UTC (9 years, 11 months ago) by schoenebeck
File size: 20768 byte(s)
* AKAI: Fixed various compilation errors for Windows.

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

Properties

Name Value
svn:executable *

  ViewVC Help
Powered by ViewVC