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 |