/[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 2574 - (hide 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 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 schoenebeck 2574 #ifdef WIN32
29 schoenebeck 2572 # 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 schoenebeck 2574 #include <unistd.h>
38     #include <dirent.h>
39     #include <sys/stat.h>
40     #include <sys/types.h>
41    
42 schoenebeck 2572 // 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 schoenebeck 2574 #ifdef WIN32
101 schoenebeck 2572 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 schoenebeck 2574 #ifdef WIN32
127 schoenebeck 2572 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 schoenebeck 2574 #ifdef WIN32
194 schoenebeck 2572 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 schoenebeck 2574 #ifdef WIN32
310     if (stat(outPath, &filestat) < 0) {
311     #else
312 schoenebeck 2572 if (lstat(outPath, &filestat) < 0) {
313 schoenebeck 2574 #endif
314 schoenebeck 2572 printf("Creating output directory '%s'...", outPath);
315     fflush(stdout);
316 schoenebeck 2574 #ifdef WIN32
317     if (mkdir(outPath) < 0) {
318     #else
319 schoenebeck 2572 if (mkdir(outPath, 0770) < 0) {
320 schoenebeck 2574 #endif
321 schoenebeck 2572 perror("failed");
322     errorOccured = true;
323     }
324     else printf("ok\n");
325     }
326     else {
327 schoenebeck 2574 #if !defined(WIN32)
328 schoenebeck 2572 if (!S_ISLNK(filestat.st_mode)) {
329 schoenebeck 2574 #endif
330 schoenebeck 2572 printf("Cannot create output directory '%s': ", outPath);
331     printf("a file of that name already exists\n");
332     errorOccured = true;
333 schoenebeck 2574 #if !defined(WIN32)
334 schoenebeck 2572 }
335 schoenebeck 2574 #endif
336 schoenebeck 2572 }
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 schoenebeck 2574 #if WIN32
454 schoenebeck 2572 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