Check for SYS/GL during library init. Reason is that
[AROS.git] / workbench / devs / AHI / Drivers / Filesave / filesave-playslave.c
blobe7b98262f154977c88c0287900056e17e39ab030
2 #include <config.h>
4 #include <exec/execbase.h>
5 #include <libraries/ahi_sub.h>
6 #include <libraries/asl.h>
7 #include <proto/exec.h>
8 #include <proto/dos.h>
9 #include <proto/intuition.h>
11 #include <string.h>
13 #include "DriverData.h"
14 #include "FileFormats.h"
15 #include "library.h"
17 #define dd ((struct FilesaveData*) AudioCtrl->ahiac_DriverData)
19 #define abs(x) ((x)<0?(-x):(x))
21 void ulong2extended (ULONG in, extended *ex);
23 /******************************************************************************
24 ** Endian conversion **********************************************************
25 ******************************************************************************/
27 #ifdef WORDS_BIGENDIAN
29 #define __htole_short(x) \
30 ((((x) & 0xff00) >> 8) | (((x) & 0x00ff) << 8))
32 #define __htole_long(x) \
33 ((((x) & 0xff000000) >> 24) | (((x) & 0x00ff0000) >> 8) | \
34 (((x) & 0x0000ff00) << 8) | (((x) & 0x000000ff) << 24))
36 unsigned short
37 htole_short( unsigned short x )
39 return (unsigned short) __htole_short( x );
42 unsigned long
43 htole_long( unsigned long x )
45 return __htole_long( x );
48 #define __htobe_short(x) (x)
49 #define __htobe_long(x) (x)
50 #define htobe_short(x) (x)
51 #define htobe_long(x) (x)
53 #else
55 #define __htole_short(x) (x)
56 #define __htole_long(x) (x)
57 #define htole_short(x) (x)
58 #define htole_long(x) (x)
60 #define __htobe_short(x) \
61 ((((x) & 0xff00) >> 8) | (((x) & 0x00ff) << 8))
63 #define __htobe_long(x) \
64 ((((x) & 0xff000000) >> 24) | (((x) & 0x00ff0000) >> 8) | \
65 (((x) & 0x0000ff00) << 8) | (((x) & 0x000000ff) << 24))
67 unsigned short
68 htobe_short( unsigned short x )
70 return (unsigned short) __htobe_short( x );
73 unsigned long
74 htobe_long( unsigned long x )
76 return __htobe_long( x );
79 #endif
82 /******************************************************************************
83 ** The slave process **********************************************************
84 ******************************************************************************/
87 #if defined( __MORPHOS__ )
89 /* For f*cks sake!!! Don't use SysBase in memcpy()! */
91 void *
92 memcpy(void *dst, const void *src, size_t len)
94 bcopy(src, dst, len);
95 return dst;
98 #endif
101 #undef SysBase
103 static void PlaySlave( struct ExecBase* SysBase );
105 #if defined( __AROS__ )
107 #include <aros/asmcall.h>
109 AROS_UFH3(void, PlaySlaveEntry,
110 AROS_UFHA(STRPTR, argPtr, A0),
111 AROS_UFHA(ULONG, argSize, D0),
112 AROS_UFHA(struct ExecBase *, SysBase, A6))
114 AROS_USERFUNC_INIT
115 PlaySlave( SysBase );
116 AROS_USERFUNC_EXIT
119 #else
121 void PlaySlaveEntry(void)
123 struct ExecBase* SysBase = *((struct ExecBase**) 4);
125 PlaySlave( SysBase );
128 #endif
130 static void PlaySlave( struct ExecBase* SysBase )
132 struct AHIAudioCtrlDrv* AudioCtrl;
133 struct DriverBase* AHIsubBase;
134 struct FilesaveBase* FilesaveBase;
136 struct EIGHTSVXheader EIGHTSVXheader = // All 0s will be filled later.
138 __htobe_long(ID_FORM), 0, __htobe_long(ID_8SVX),
139 __htobe_long(ID_VHDR), __htobe_long(sizeof(Voice8Header)),
146 sCmpNone,
147 __htobe_long(0x10000)
149 __htobe_long(ID_BODY), 0
152 struct AIFFheader AIFFheader = // All 0s will be filled later.
154 __htobe_long(ID_FORM), 0, __htobe_long(ID_AIFF),
155 __htobe_long(ID_COMM), __htobe_long(sizeof(CommonChunk)),
159 __htobe_short(16),
161 0, { 0, 0 }
164 __htobe_long(ID_SSND), 0,
171 struct AIFCheader AIFCheader = // All 0s will be filled later.
173 __htobe_long(ID_FORM), 0, __htobe_long(ID_AIFC),
174 __htobe_long(ID_FVER), __htobe_long(sizeof(FormatVersionHeader)),
176 __htobe_long(AIFCVersion1)
178 __htobe_long(ID_COMM), __htobe_long(sizeof(ExtCommonChunk)),
182 __htobe_short(16),
184 0, { 0, 0 }
186 __htobe_long(NO_COMPRESSION),
187 { sizeof("not compressed") - 1,
188 'n','o','t',' ','c','o','m','p','r','e','s','s','e','d' }
190 __htobe_long(ID_SSND), 0,
197 struct STUDIO16FILE S16header = // All 0s will be filled later.
199 __htobe_long(S16FID),
201 __htobe_long(S16FINIT),
202 __htobe_short(S16_VOL_0),
218 struct WAVEheader WAVEheader = // All 0s will be filled later.
220 __htobe_long(ID_RIFF), 0, __htobe_long(ID_WAVE),
221 __htobe_long(ID_fmt), __htole_long( sizeof(FormatChunk) ),
223 __htole_short( WAVE_PCM ),
228 __htole_short( 16 )
230 __htobe_long(ID_data), 0
233 BPTR lock = 0,cd = 0,file = 0, file2 = 0;
234 LONG maxVolume = 0;
235 ULONG signals, i, samplesAdd =0, samples = 0, length = 0;
236 ULONG offset = 0, bytesInBuffer = 0, samplesWritten = 0, bytesWritten = 0;
238 /* Note that in OS4, we cannot call FindTask(NULL) here, since IExec
239 * is inside AHIsubBase! */
240 AudioCtrl = (struct AHIAudioCtrlDrv*) FindTask(NULL)->tc_UserData;
241 AHIsubBase = (struct DriverBase*) dd->fs_AHIsubBase;
242 FilesaveBase = (struct FilesaveBase*) AHIsubBase;
244 // We cannot handle stereo 8SVXs!
245 if( (dd->fs_Format == FORMAT_8SVX) &&
246 (AudioCtrl->ahiac_Flags & AHIACF_STEREO) )
248 goto quit;
251 if((dd->fs_SlaveSignal = AllocSignal(-1)) == -1)
253 goto quit;
256 if(!(lock = Lock(dd->fs_FileReq->fr_Drawer, ACCESS_READ)))
258 goto quit;
261 cd = CurrentDir(lock);
263 switch(dd->fs_Format)
265 case FORMAT_8SVX:
266 if(!(file = Open(dd->fs_FileReq->fr_File, MODE_NEWFILE))) goto quit;
267 Write(file, &EIGHTSVXheader, sizeof EIGHTSVXheader);
268 break;
270 case FORMAT_AIFF:
271 if(!(file = Open(dd->fs_FileReq->fr_File, MODE_NEWFILE))) goto quit;
272 Write(file, &AIFFheader, sizeof AIFFheader);
273 break;
275 case FORMAT_AIFC:
276 if(!(file = Open(dd->fs_FileReq->fr_File, MODE_NEWFILE))) goto quit;
277 Write(file, &AIFCheader, sizeof AIFCheader);
278 break;
280 case FORMAT_S16:
281 if (AudioCtrl->ahiac_Flags & AHIACF_STEREO)
283 char filename[256];
284 int len;
286 strncpy (filename, dd->fs_FileReq->fr_File, sizeof(filename) - 3);
287 len = strlen(filename);
289 if(len >= 2 && filename[len - 2] == '_'
290 && (filename[len - 1] == 'L' || filename[len - 1] == 'R'))
292 filename[len - 1] = 'L';
294 else
296 strcat (filename, "_L");
299 if(!(file = Open(filename, MODE_NEWFILE))) goto quit;
301 filename[strlen(filename) - 1] = 'R';
302 if(!(file2 = Open(filename, MODE_NEWFILE))) goto quit;
304 Write(file, &S16header, sizeof S16header);
305 Write(file2, &S16header, sizeof S16header);
307 else
309 if(!(file = Open(dd->fs_FileReq->fr_File, MODE_NEWFILE))) goto quit;
310 Write(file, &S16header, sizeof S16header);
312 break;
314 case FORMAT_WAVE:
315 if(!(file = Open(dd->fs_FileReq->fr_File, MODE_NEWFILE))) goto quit;
316 Write(file, &WAVEheader, sizeof WAVEheader);
317 break;
320 // Everything set up. Tell Master we're alive and healthy.
321 Signal((struct Task *)dd->fs_MasterTask,1L<<dd->fs_MasterSignal);
323 for(;;)
325 signals = SetSignal(0L,0L);
326 if(signals & (SIGBREAKF_CTRL_C | 1L<<dd->fs_SlaveSignal))
328 break;
331 CallHookPkt(AudioCtrl->ahiac_PlayerFunc, AudioCtrl, NULL);
332 CallHookPkt(AudioCtrl->ahiac_MixerFunc, AudioCtrl, dd->fs_MixBuffer);
334 samplesAdd = AudioCtrl->ahiac_BuffSamples;
335 samples = samplesAdd;
337 if(AudioCtrl->ahiac_Flags & AHIACF_STEREO)
339 samples <<= 1;
342 // Search for loudest part in sample
343 if(AudioCtrl->ahiac_Flags & AHIACF_HIFI)
345 for(i = 0; i < samples; i++)
346 if(abs(((LONG *)dd->fs_MixBuffer)[i]) > maxVolume)
347 maxVolume = abs(((LONG *)dd->fs_MixBuffer)[i]);
349 else
351 for(i = 0; i< samples; i++)
352 if(abs(((WORD *)dd->fs_MixBuffer)[i]) > maxVolume)
353 maxVolume = abs(((WORD *)dd->fs_MixBuffer)[i]);
356 if((AudioCtrl->ahiac_Flags & AHIACF_STEREO) && dd->fs_Format == FORMAT_S16)
358 samples >>= 1; // Two buffers instead
361 if(offset+samples >= dd->fs_SaveBufferSize)
363 if((ULONG) Write(file, dd->fs_SaveBuffer, bytesInBuffer) != bytesInBuffer)
365 break;
367 if(file2 != 0) {
368 if((ULONG) Write(file2, dd->fs_SaveBuffer2, bytesInBuffer) != bytesInBuffer)
370 break;
373 offset = 0;
374 bytesInBuffer = 0;
377 switch(dd->fs_Format)
379 case FORMAT_8SVX:
380 if(AudioCtrl->ahiac_Flags & AHIACF_HIFI)
382 BYTE *dest = &((BYTE *) dd->fs_SaveBuffer)[offset];
383 LONG *source = dd->fs_MixBuffer;
385 for(i = 0; i < samples; i++)
386 *dest++ = *source++ >> 24;
388 else
390 BYTE *dest = &((BYTE *) dd->fs_SaveBuffer)[offset];
391 WORD *source = dd->fs_MixBuffer;
393 for(i = 0; i < samples; i++)
394 *dest++ = *source++ >> 8;
396 length = samples;
397 break;
399 case FORMAT_AIFF:
400 case FORMAT_AIFC:
401 if(AudioCtrl->ahiac_Flags & AHIACF_HIFI)
403 WORD *dest = &((WORD *) dd->fs_SaveBuffer)[offset];
404 LONG *source = dd->fs_MixBuffer;
406 for(i = 0; i < samples; i++)
408 *dest++ = htobe_short( *source++ >> 16 );
411 else
413 WORD *dest = &((WORD *) dd->fs_SaveBuffer)[offset];
414 WORD *source = dd->fs_MixBuffer;
416 for(i = 0; i < samples; i++)
418 *dest++ = htobe_short( *source++ );
421 length = samples*2;
422 break;
424 case FORMAT_S16:
425 switch(AudioCtrl->ahiac_Flags & (AHIACF_HIFI | AHIACF_STEREO))
427 case 0:
429 WORD *dest = &((WORD *) dd->fs_SaveBuffer)[offset];
430 WORD *source = dd->fs_MixBuffer;
432 for(i = 0; i < samples; i++)
434 *dest++ = htobe_short( *source++ );
437 break;
440 case AHIACF_STEREO:
442 WORD *dest1 = &((WORD *) dd->fs_SaveBuffer)[offset];
443 WORD *dest2 = &((WORD *) dd->fs_SaveBuffer2)[offset];
444 WORD *source = dd->fs_MixBuffer;
446 for(i = 0; i < samples; i++)
448 *dest1++ = htobe_short( *source++ );
449 *dest2++ = htobe_short( *source++ );
452 break;
455 case AHIACF_HIFI:
457 WORD *dest = &((WORD *) dd->fs_SaveBuffer)[offset];
458 LONG *source = dd->fs_MixBuffer;
460 for(i = 0; i < samples; i++)
462 *dest++ = htobe_short( *source++ >> 16 );
465 break;
468 case (AHIACF_HIFI | AHIACF_STEREO):
470 WORD *dest1 = &((WORD *) dd->fs_SaveBuffer)[offset];
471 WORD *dest2 = &((WORD *) dd->fs_SaveBuffer2)[offset];
472 LONG *source = dd->fs_MixBuffer;
474 for(i = 0; i < samples; i++)
476 *dest1++ = htobe_short( *source++ >> 16 );
477 *dest2++ = htobe_short( *source++ >> 16 );
480 break;
484 length = samples*2;
485 break;
487 case FORMAT_WAVE:
488 if(AudioCtrl->ahiac_Flags & AHIACF_HIFI)
490 WORD *dest = &((WORD *) dd->fs_SaveBuffer)[offset];
491 LONG *source = dd->fs_MixBuffer;
493 for(i = 0; i < samples; i++)
495 *dest++ = htole_short( *source++ >> 16 );
498 else
500 WORD *dest = &((WORD *) dd->fs_SaveBuffer)[offset];
501 WORD *source = dd->fs_MixBuffer;
503 for(i = 0; i < samples; i++)
505 *dest++ = htole_short( *source++ );
508 length = samples*2;
509 break;
512 offset += samples;
513 samplesWritten += samplesAdd;
514 bytesWritten += length;
515 bytesInBuffer += length;
518 Write(file, dd->fs_SaveBuffer, bytesInBuffer);
519 if(file2 != 0)
521 Write(file2, dd->fs_SaveBuffer2, bytesInBuffer);
524 switch(dd->fs_Format)
526 case FORMAT_8SVX:
527 EIGHTSVXheader.FORMsize = htobe_long(sizeof(EIGHTSVXheader)-8+bytesWritten);
528 EIGHTSVXheader.VHDRchunk.oneShotHiSamples = htobe_long(samplesWritten);
529 EIGHTSVXheader.VHDRchunk.samplesPerSec = htobe_short(AudioCtrl->ahiac_MixFreq);
530 EIGHTSVXheader.BODYsize = htobe_long(bytesWritten);
531 if(bytesWritten & 1)
532 FPutC(file,'\0'); // Pad to even
533 Seek(file,0,OFFSET_BEGINNING);
534 Write(file,&EIGHTSVXheader,sizeof EIGHTSVXheader);
535 break;
537 case FORMAT_AIFF:
538 AIFFheader.FORMsize = htobe_long(sizeof(AIFFheader)-8+bytesWritten);
539 AIFFheader.COMMchunk.numChannels = htobe_short((AudioCtrl->ahiac_Flags & AHIACF_STEREO ? 2 : 1));
540 AIFFheader.COMMchunk.numSampleFrames = htobe_long(samplesWritten);
541 ulong2extended(AudioCtrl->ahiac_MixFreq,&AIFFheader.COMMchunk.sampleRate);
542 AIFFheader.SSNDsize = htobe_long(sizeof(SampledSoundHeader)+bytesWritten);
543 Seek(file,0,OFFSET_BEGINNING);
544 Write(file,&AIFFheader,sizeof AIFFheader);
545 break;
547 case FORMAT_AIFC:
548 AIFCheader.FORMsize = htobe_long(sizeof(AIFCheader)-8+bytesWritten);
549 AIFCheader.COMMchunk.numChannels = htobe_short((AudioCtrl->ahiac_Flags & AHIACF_STEREO ? 2 : 1));
550 AIFCheader.COMMchunk.numSampleFrames = htobe_long(samplesWritten);
551 ulong2extended(AudioCtrl->ahiac_MixFreq,&AIFCheader.COMMchunk.sampleRate);
552 AIFCheader.SSNDsize = htobe_long(sizeof(SampledSoundHeader)+bytesWritten);
553 Seek(file,0,OFFSET_BEGINNING);
554 Write(file,&AIFCheader,sizeof AIFCheader);
555 break;
557 case FORMAT_S16:
558 S16header.S16F_RATE = htobe_long(AudioCtrl->ahiac_MixFreq);
559 S16header.S16F_SAMPLES0 =
560 S16header.S16F_SAMPLES1 = htobe_long(samplesWritten);
561 S16header.S16F_SAMPLES2 = htobe_long(samplesWritten - 1);
562 if (file2 == 0)
564 S16header.S16F_PAN = htobe_long(S16_PAN_MID);
566 else
568 S16header.S16F_PAN = htobe_long(S16_PAN_LEFT);
571 Seek(file, 0, OFFSET_BEGINNING);
572 Write(file, &S16header, sizeof S16header);
573 if(file2 != 0)
575 S16header.S16F_PAN = htobe_long(S16_PAN_RIGHT);
576 Seek(file2,0,OFFSET_BEGINNING);
577 Write(file2, &S16header, sizeof S16header);
579 break;
581 case FORMAT_WAVE:
583 short num_channels;
584 short block_align;
586 num_channels = AudioCtrl->ahiac_Flags & AHIACF_STEREO ? 2 : 1;
587 block_align = num_channels * 16 / 8;
589 WAVEheader.FORMsize = htole_long( sizeof(WAVEheader)-8+bytesWritten );
590 WAVEheader.FORMATchunk.numChannels = htole_short( num_channels );
591 WAVEheader.FORMATchunk.samplesPerSec = htole_long( AudioCtrl->ahiac_MixFreq );
592 WAVEheader.FORMATchunk.avgBytesPerSec = htole_long( AudioCtrl->ahiac_MixFreq * block_align );
593 WAVEheader.FORMATchunk.blockAlign = htole_short( block_align );
594 WAVEheader.DATAsize = htole_long( bytesWritten );
595 Seek(file,0,OFFSET_BEGINNING);
596 Write(file,&WAVEheader,sizeof WAVEheader);
597 break;
601 if(AudioCtrl->ahiac_Flags & AHIACF_HIFI)
602 maxVolume >>=16;
604 if(maxVolume != 0)
606 Req("Rendering finished.\nTo futher improve the quality of the sample,\n"
607 "you can raise the volume to %ld%% and render again.",
608 3276800/maxVolume );
611 quit:
612 if(file)
614 Close(file);
616 if(file2)
618 Close(file2);
620 if(lock)
622 CurrentDir(cd);
623 UnLock(lock);
626 Forbid();
627 dd->fs_SlaveTask = NULL;
628 FreeSignal(dd->fs_SlaveSignal);
629 dd->fs_SlaveSignal = -1;
630 // Tell the Master we're dying
631 Signal((struct Task *)dd->fs_MasterTask,1L<<dd->fs_MasterSignal);
632 // Multitaking will resume when we are dead.
636 ** Apple's 80-bit SANE extended has the following format:
638 1 15 1 63
639 +-+-------------+-+-----------------------------+
640 |s| e |i| f |
641 +-+-------------+-+-----------------------------+
642 msb lsb msb lsb
644 The value v of the number is determined by these fields as follows:
645 If 0 <= e < 32767, then v = (-1)^s * 2^(e-16383) * (i.f).
646 If e == 32767 and f == 0, then v = (-1)^s * (infinity), regardless of i.
647 If e == 32767 and f != 0, then v is a NaN, regardless of i.
650 void ulong2extended (ULONG in, extended *ex)
652 ex->exponent = 31+16383;
653 ex->mantissa[1] = 0;
654 while(!(in & 0x80000000))
656 ex->exponent--;
657 in <<= 1;
659 ex->mantissa[0] = in;
661 ex->exponent = htobe_short( ex->exponent );
662 ex->mantissa[0] = htobe_long( ex->mantissa[0] );
663 ex->mantissa[1] = htobe_long( ex->mantissa[1] );