
/*********************************************************************************
*	objects by jf
*	all the real code lifted from
/*********************************************************************************
*
*  PROGRAM:     sine.c
*
*  AUTHOR:      Leonard Manzara
*
*  THIS PROGRAM GENERATES A SINE WAVE ON THE DSP AND PLAYS IT THROUGH
*  THE NeXT DAC.  BASED HEAVILY ON dsp_example_3.
*  COMPILE THIS WITH:   cc sine.c -ansi -lm -lsys_s -O
*  THE DSP ASSEMBLY PROGRAM IS:  sine.asm   
*
*********************************************************************************/

/* Generated by Interface Builder */

#import <stdlib.h>
#import <stdio.h>
#import <libc.h>	/* for sleep */
#import <appkit/defaults.h>		/* NXArgv */
#import <appkit/Slider.h>
#import <appkit/Application.h>	/* NXApp */
#import <text/pathutil.h>		/* so we can strip out path name to find the .lod file when launching*/


#import "SineController.h"

@implementation SineController

static	char tempName[1024];

/* use the appDidInit to setup all of the port communication with the DSP */
- appDidInit:sender
{
	
/*  INITIALIZE DMA STREAMING VARIABLES  */
low_water = 48*1024;
high_water = 64*1024;
read_width = 2;
read_buf_size = 512;

/*  GET THE DEVICE PORT FOR THE SOUND/DSP DRIVER ON THE LOCAL MACHINE  */
k_err = netname_look_up(name_server_port,"","sound",&dev_port);
if (k_err != KERN_SUCCESS) {
  mach_error("netname lookup failure ",k_err);
  return(0);
}

/*  GET THE OWNER PORT  */
k_err = port_allocate(task_self(),&owner_port);
if (k_err != KERN_SUCCESS) {
  mach_error("Cannot allocate owner port ",k_err);
  return(0);
}

/*  BECOME OWNER OF DSP RESOURCES  */
temp_port = owner_port;
k_err = snddriver_set_dsp_owner_port(dev_port,owner_port,&temp_port);
if (k_err != KERN_SUCCESS) {
  mach_error("Cannot become owner of dsp resources ",k_err);
  return(0);
}

/*  GET THE DSP COMMAND PORT  */
k_err = snddriver_get_dsp_cmd_port(dev_port,owner_port,&cmd_port);
if (k_err != KERN_SUCCESS) {
  mach_error("Cannot acquire command port ",k_err);
  return(0);
}

/*  ACQUIRE OWNERSHIP OF THE SOUND OUTPUT DEVICE  */
k_err = snddriver_set_sndout_owner_port(dev_port,owner_port,&temp_port);
if (k_err != KERN_SUCCESS) {
  mach_error("Cannot become owner of sound out device ",k_err);
  return(0);
}

/*  SET UP TO STREAM DATA FROM THE DSP TO THE SOUND DEVICE  */
protocol = 0;
k_err = snddriver_stream_setup(dev_port,owner_port,SNDDRIVER_STREAM_DSP_TO_SNDOUT_44,
			       read_buf_size,read_width,low_water,high_water,
			       &protocol,&read_port);
if (k_err != KERN_SUCCESS) {
  mach_error("Cannot set up stream from DSP ",k_err);
  return(0);
}

/*  SET THE DSP PROTOCOL  */
k_err = snddriver_dsp_protocol(dev_port,owner_port,protocol);
if (k_err != KERN_SUCCESS) {
  mach_error("Cannot set up DSP protocol ",k_err);
  return(0);
}

/*  ALLOCATE A PORT FOR REPLIES  */
k_err = port_allocate(task_self(),&reply_port);
if (k_err != KERN_SUCCESS) {
  mach_error("Cannot allocate reply port ",k_err);
  return(0);
}

/*  PARSE THE .LOD ASSEMBLY FILE AND BOOT THE DSP WITH IT  */
	strcpy(tempName, parentname(NXArgv[0]));
	strcat(tempName,"/sine.lod");
s_err = SNDReadDSPfile(tempName,&dspStruct,NULL);
if (s_err != SND_ERR_NONE) {
  fprintf(stderr,"Cannot parse DSP load image: %s\n",SNDSoundError(s_err));
  return(0);
}

s_err = SNDBootDSP(dev_port,owner_port,dspStruct);
if (s_err != SND_ERR_NONE) {
  fprintf(stderr,"Cannot boot dsp: %s\n",SNDSoundError(s_err));
  return(0);
}

/*  START STREAM FROM THE DSP  */
k_err = snddriver_stream_start_reading(read_port,NULL,
				       read_count,0,
				       0,0,0,0,0,0,reply_port);
if (k_err != KERN_SUCCESS) {
  mach_error("Cannot enqueue read request ",k_err);
  return(0);
}

	/*  SEND INTIAL TABLE VALUE TO DSP  */
	k_err = snddriver_dspcmd_req_condition(cmd_port,SNDDRIVER_ISR_HF3,
					SNDDRIVER_ISR_HF3,SNDDRIVER_HIGH_PRIORITY,PORT_NULL);
	if (k_err != KERN_SUCCESS) {
	  mach_error("Cannot request condition ",k_err);
	  return(0);
	}
	reply = 0;
	k_err = snddriver_dsp_write(cmd_port,&reply,1,4,SNDDRIVER_MED_PRIORITY);
	if (k_err != KERN_SUCCESS) {
	  mach_error("Cannot write to DSP ",k_err);
 	 return(0);
	}
	k_err = snddriver_dspcmd_req_condition(cmd_port,SNDDRIVER_ISR_HF3,0,
				       SNDDRIVER_HIGH_PRIORITY,PORT_NULL);
	if (k_err != KERN_SUCCESS) {
	  mach_error("Cannot request condition ",k_err);
	  return(0);
	}


	/*  SEND HOST COMMAND TO THE DSP CHIP;  VECTOR = P:$0026
 	   CAUSES PROGRAM CONTROL TO JMP TO MAIN, WHERE SOUND SAMPLES ARE SENT 
  	  NOTE THAT THE HOST COMMAND IS THE VECTOR ADDRESS DIVIDED BY 2  */
	k_err = snddriver_dsp_host_cmd(cmd_port,(u_int)0x13,SNDDRIVER_HIGH_PRIORITY);
	if (k_err != KERN_SUCCESS) {
	  mach_error("Cannot send host command ",k_err);
	  return(0);
	}

	return self;
}

- takeSkipValueFrom:sender
{
	/*  SEND INTIAL TABLE VALUE TO DSP  */
	//k_err = snddriver_dspcmd_req_condition(cmd_port,SNDDRIVER_ISR_HF3,
	//				SNDDRIVER_ISR_HF3,SNDDRIVER_HIGH_PRIORITY,PORT_NULL);
	//if (k_err != KERN_SUCCESS) {
	//  mach_error("Cannot request condition ",k_err);
	 // return(0);
	//}
	reply = [sender intValue];
	k_err = snddriver_dsp_write(cmd_port,&reply,1,4,SNDDRIVER_MED_PRIORITY);
	if (k_err != KERN_SUCCESS) {
	  mach_error("Cannot write to DSP ",k_err);
 	 return(0);
	}
	//k_err = snddriver_dspcmd_req_condition(cmd_port,SNDDRIVER_ISR_HF3,0,
	//			       SNDDRIVER_HIGH_PRIORITY,PORT_NULL);
	//if (k_err != KERN_SUCCESS) {
	//  mach_error("Cannot request condition ",k_err);
	//  return(0);
	//}

    return self;
}

- stopDSP:sender
{
	/* send a 0 down to avoid the popping on the sound after we quit  (DOESN'T work) */
	reply = 0;
	k_err = snddriver_dsp_write(cmd_port,&reply,1,4,SNDDRIVER_MED_PRIORITY);
	if (k_err != KERN_SUCCESS) {
	  mach_error("Cannot write to DSP ",k_err);
 	 return(0);
	}
	sleep(1);
	/*  PLAY THE SINE TONE UNTIL PROGRAM TERMINATED.  VECTOR = p:$0028
	CAUSES PROGRAM CONTROL TO JMP TO RESET, EFFECTIVELY STOPPING SAMPLE OUT  */
	k_err = snddriver_dsp_host_cmd(cmd_port,(u_int)0x14,SNDDRIVER_HIGH_PRIORITY);
	if (k_err != KERN_SUCCESS) {
	  mach_error("Cannot send host command ",k_err);
	  return(0);
	}
	return self;
}

- terminate:sender
/* tied from menu */
{
	[self stopDSP:sender];
	[NXApp terminate:sender];
	return self;
}

- windowWillClose:sender
/* connection in nib says we are window delegate */
{
	[self stopDSP:sender];
}

@end
