
/******************************************************************************/
/* FILE    :   sound.c -  Module to Play with Sun sounds                      */
/* AUTHOR  :   Andreas Sorgatz                                                */
/* CREATED :   22.02.94                                                       */
/* CHANGED :   13.05.94                                                       */
/*                                                                            */
/* play       - Play a MuPAD sound                                            */
/* new        - Load a sound-file into a MuPAD sound object                   */
/* audio_free - Try to free a busy audio-device                               */
/*                                                                            */
/* Sounds will be embeded into DOM_STRINGs, where the string contains the     */
/* filename and a sound-signature as a prefix. The data-field of the Cate-    */
/* gory will be expanded by a  "long",  to give the size of the sound and     */
/* a field of "char", which contains the sound.  Sounds can't be saved in     */
/* MuPAD-files !                                                              */
/******************************************************************************/
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include "MMT_tool.c" 

/*** Definements **************************************************************/

#define SND_BUF_LEN	1024L
#define SND_SUFFIX	".au"

#define SND_ERR_OK	0L                    /*** It's all right           ***/
#define SND_ERR_FILE	1L                    /*** Can't open sound-file    ***/
#define SND_ERR_AUDIO	2L                    /*** Can't open audio-device  ***/
#define SND_ERR_PLAY	3L                    /*** Can't read or play sound ***/
#define SND_ERR_NOSND	4L                    /*** Sound-object expected    ***/

/*** Global Variables *********************************************************/

static CONST char *magic = "@SND - ";             /*** signature of a sound ***/

static char	*SND_err_strg[] = {                     /*** error-messages ***/
		"",
		"Can't open sound-file",
		"Can't open audio-device",
		"Can't read or play sound",
		"That's not a Sound-object"
};

static FILE	*audio = NULL;     /*** file-descriptor of the audio-device ***/

/*** Prototypes of LowLevel-Functions *****************************************/

S_Pointer SND_load_file	( char      *name );
long      SND_play	( S_Pointer  snd  );
long      SND_play_file	( char      *name );

/*** LowLevel-Functions *******************************************************/

/******************************************************************************/
/* NAME     :   SND_load_file                                                 */
/* PARAMETER:   name - (C-String) Name of sound-file                          */
/* FUNCTION :   Create a DOM_STRING by using the strings 'magic' and 'name'   */
/*              and read the given sound-file into it's data-field.           */
/******************************************************************************/
S_Pointer SND_load_file( char *name )
{
	FILE		*sound;
	char		*pnt, buf[SND_BUF_LEN], fullname[SND_BUF_LEN];
	struct stat	 st;
	long		 size;
	S_Pointer	 snd;

	/*** Look for 'name' in the directories given by READ_PATH, in ","  ***/
	/*** and in the MuPAD modul-path                                    ***/
	
	if( MDM_which(name,SND_SUFFIX,fullname) != MDMC_OK ) {
		if( MDM_which(name,"",fullname) != MDMC_OK ) {
			return( MMMNULL );
		}
	}
	
	/*** Open sound-file and get it's size ********************************/
	
	if( (sound = fopen(fullname,"r")) == NULL ) {
		return( MMMNULL );
	}
	if( fstat(fileno(sound),&st) == -1 ) {
		fclose( sound );
		return( MMMNULL );
	}
	size = st.st_size;

	/*** Create a DOM_STRING from the sound information string ************/
	
	if( (int)(strlen(magic)+strlen(name)) < SND_BUF_LEN ) {
		sprintf( buf, "%s%s", magic, name );
	} else {
		sprintf( buf, "%s", magic, "unknown sound" );
	}
	snd = MMT_c2m_string( buf );

	/*** Expand the data-field of the DOM_STRING **************************/
	
	MMMresize( &snd, sizeof(CATEGORY)+sizeof(long)+size );
	
	/*** Insert sound data ************************************************/
	
	pnt = MMMZ( &snd, char, MMMwrite ) + sizeof(CATEGORY);

	*((long*) pnt) = size;  pnt += sizeof(long);

	if( fread(pnt,1,size,sound) != size ) {
		fclose( sound );
		MMMfree( snd );
		return( MMMNULL );
	}
	fclose( sound );
	MMMinactiv( &snd );

	return( snd );
}

/******************************************************************************/
/* NAME     :   SND_play                                                      */
/* PARAMETER:   sound - (DOM_STRING) Special Sound-Category                   */
/* FUNCTION :   Write the given sound to the audio-device                     */
/******************************************************************************/
long SND_play( S_Pointer snd )
{
	char		*strg, *pnt;
	long		 size;
	
	/*** Check for magic, the sound-signature *****************************/
	
	strg = MMT_m2c_string_adr( snd );
	if( strncmp(strg,magic,strlen(magic)) != 0 ) {
		return( SND_ERR_NOSND );
	}
	
	/*** Open the audio-device and write sound-data to it *****************/
	
	if( audio != NULL ) { fclose( audio );
	}
	if( (audio = fopen("/dev/audio","w")) == NULL ) {
		return( SND_ERR_AUDIO );
	}
	pnt = MMMZ( &snd, char, MMMwrite ) + sizeof(CATEGORY);
	size = *((long*) pnt);  pnt += sizeof(long);

	while( size-- > 0L ) { fputc(*pnt++,audio); 
	}
	fclose( audio ); audio = NULL;

	return( SND_ERR_OK );
}

/******************************************************************************/
/*** Module-Functions *********************************************************/
/******************************************************************************/

/******************************************************************************/
/* MODUL_FUNC: free_audio()                                                   */
/* Try ro reset a busy audio-device                                           */
/******************************************************************************/
MODUL_FUNC( free_audio )
{
	MMT_init( "free_audio", MMT_NOP, MEVC_NULL );
	MMT_check_params( 0L );
	if( audio != NULL ) fclose( audio );
	MMT_return( MMT_copy(MMT_null) )
}

/******************************************************************************/
/* MODUL_FUNC: new( filename : DOM_STRING )                                 */
/* Load the given sound-file into a (special expanded) DOM_STRING.            */
/******************************************************************************/
MODUL_FUNC( new )
{
	S_Pointer	 snd;
	char		*name;
	
	MMT_init( "new", MMT_NOP, MEVC_STRING );
	MMT_check_params( 1L );
	MMT_check_param ( 1L, CAT_STRING );

	name = MMT_m2c_string_adr( MMT_param(1L) );
	snd  = SND_load_file( name );
	
	if( snd == MMMNULL ) { MMT_error( "Can't load sound" )
	}
	MMT_return( snd );
}

/******************************************************************************/
/* MODUL_FUNC: play( sound : DOM_STRING )                                     */
/* Play the sound of the given (special expanded) DOM_STRING 'sound'.         */
/******************************************************************************/
MODUL_FUNC ( play )
{
	long		 error;
	S_Pointer	 tmp;

	MMT_init( "play", MMT_NOP, MEVC_NULL );
	MMT_check_params( 1L );
	MMT_check_param ( 1L, CAT_STRING );

	if( SND_play(MMT_param(1L)) != SND_ERR_OK ) {
		MMT_error( "Can't play sound" )
	}
	MMT_return( MMT_copy(MMT_null) )
}

