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

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

Parent Directory Parent Directory | Revision Log Revision Log


Revision 2572 - (hide 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 schoenebeck 2572 /*
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