/*
**	termBeep.c
**
**	Sound support routines
**
**	Copyright © 1990-1992 by Olaf `Olsen' Barthel & MXM
**		All Rights Reserved
*/

#include "termGlobal.h"

	/* IFF Sound `8SVX' voice header. */

struct Voice8Header
{
	ULONG	oneShotHiSamples,	/* # samples in the high octave 1-shot part */
		repeatHiSamples,	/* # samples in the high octave repeat part */
		samplesPerHiCycle;	/* # samples/cycle in high octave, else 0 */
	UWORD	samplesPerSec;		/* data sampling rate */
	UBYTE	ctOctave,		/* # of octaves of waveforms */
		sCompression;		/* data compression technique used */
	LONG	volume;			/* playback nominal volume from 0 to Unity
					 * (full volume). Map this value into
					 * the output hardware's dynamic range.
					 */
};

	/* CreateBeep():
	 *
	 *	Set up the audio.device for a decent beep sound.
	 */

BYTE
CreateBeep()
{
		/* Do we already have the resources we need? */

	if(!AudioBlock)
	{
		struct MsgPort *AudioPort;

			/* No sound so far. */

		SoundPlayed = FALSE;

			/* Create the IO reply port. */

		if(AudioPort = (struct MsgPort *)CreateMsgPort())
		{
				/* Create the audio IO info. */

			if(AudioBlock = (struct IOAudio *)CreateIORequest(AudioPort,sizeof(struct IOAudio)))
			{
					/* Open audio.device */

				if(!OpenDevice(AUDIONAME,0,AudioBlock,0))
					return(TRUE);

				DeleteIORequest(AudioBlock);
			}

			DeleteMsgPort(AudioPort);
		}

		AudioBlock = NULL;

		return(FALSE);
	}
	else
		return(TRUE);
}

	/* DeleteBeep():
	 *
	 *	Remove the data allocated for the beep sound.
	 */

VOID
DeleteBeep()
{
	if(AudioBlock)
	{
		if(AudioBlock -> ioa_Request . io_Device)
			CloseDevice(AudioBlock);

		if(AudioBlock -> ioa_Request . io_Message . mn_ReplyPort)
			DeleteMsgPort(AudioBlock -> ioa_Request . io_Message . mn_ReplyPort);

		DeleteIORequest(AudioBlock);

		AudioBlock = NULL;
	}

	if(HasSound)
	{
		FreeVec(SoundInfo . Data);

		HasSound = FALSE;
	}
}

	/* OpenSound(UBYTE *Name):
	 *
	 *	Load an IFF-8SVX sound file instead of the standard
	 *	beep (yes, this is a zany feature nobody will ever need!).
	 */

BYTE
OpenSound(UBYTE *Name)
{
	STATIC ULONG SoundProps[] = { ID_8SVX, ID_VHDR };

	struct IFFHandle	*Handle;
	struct StoredProperty	*Prop;
	struct Voice8Header	*VoiceHeader;

	BYTE			 Success = FALSE;

		/* Allocate an IFF handle. */

	if(Handle = AllocIFF())
	{
			/* Open the file. */

		if(Handle -> iff_Stream = Open(Name,MODE_OLDFILE))
		{
				/* Say it's a DOS file. */

			InitIFFasDOS(Handle);

				/* Open the file for reading. */

			if(!OpenIFF(Handle,IFFF_READ))
			{
					/* Remember VHDR-chunks encountered. */

				if(!PropChunks(Handle,SoundProps,1))
				{
						/* Stop at the body chunk. */

					if(!StopChunk(Handle,ID_8SVX,ID_BODY))
					{
							/* Start scanning... */

						if(!ParseIFF(Handle,IFFPARSE_SCAN))
						{
								/* Obtain the stored VHDR-chunk. */

							if(Prop = FindProp(Handle,ID_8SVX,ID_VHDR))
							{
								VoiceHeader = (struct Voice8Header *)Prop -> sp_Data;

									/* Compressed data not supported so far. */

								if(!VoiceHeader -> sCompression)
								{
									struct ContextNode *ContextNode;

										/* Inquire current chunk. */

									if(ContextNode = CurrentChunk(Handle))
									{
											/* We don't support double-buffering, this
											 * is only a *simple* example.
											 */

										if(ContextNode -> cn_Size < 102400)
										{
												/* Allocate the data storage. */

											if(SoundInfo . Data = AllocVec(ContextNode -> cn_Size,MEMF_CHIP|MEMF_CLEAR))
											{
													/* Play either the one-shot or the continuous
													 * part, not both.
													 */

												SoundInfo . Length	= VoiceHeader -> oneShotHiSamples ? VoiceHeader -> oneShotHiSamples : VoiceHeader -> repeatHiSamples;

													/* Calculate recording rate. */

												SoundInfo . Rate	= (GfxBase -> DisplayFlags & PAL ? 3546895 : 3579545) / VoiceHeader -> samplesPerSec;

													/* Calculate volume. */

												SoundInfo . Volume	= (VoiceHeader -> volume * 64) / 0x10000;

													/* Read the data. */

												if(ReadChunkBytes(Handle,SoundInfo . Data,ContextNode -> cn_Size))
													Success = TRUE;
												else
													FreeVec(SoundInfo . Data);
											}
										}
									}
								}
							}
						}
					}
				}

					/* Make iffparse clean up after us. */

				CloseIFF(Handle);
			}

				/* Close the DOS handle. */

			Close(Handle -> iff_Stream);
		}

			/* Free the IFF handle. */

		FreeIFF(Handle);
	}

		/* Remember success/failure. */

	HasSound = Success;

	return(Success);
}
