
/* Generated by Interface Builder */

#import "SlowPlay.h"
#define DMASIZE 4096

static port_t reply_port;
static int playing;


static void iterate(DPSTimedEntry iter, double now, void *senderObject)
{
    [(id) senderObject checkTime];
}


@implementation SlowPlay

- setWarningPanel:anObject
{

    openPanel = [OpenPanel new];
    [openPanel setDelegate:self];
    warningPanel = anObject;
    soundLength = 0;
    config = SNDDRIVER_STREAM_THROUGH_DSP_TO_SNDOUT_44;
    return self;
}

- open
{

    [displayView makeKeyAndOrderFront:self];
    SNDReadDSPfile([self findPath:"/DSP_Code/SlowPlay.lod"], &Effect, NULL);
    port_allocate(task_self(),&reply_port);
    reply_msg = (msg_header_t *)malloc(MSG_SIZE_MAX);
    reply_msg->msg_size = MSG_SIZE_MAX;
    reply_msg->msg_local_port = reply_port;
    return self;
}

- buttonPush:sender
{
int tag,k_err;
short *startPlay;

    [warningPanel close];
    tag = [[sender selectedCell] tag];
    switch(tag)
    {
	case 0 : [self openFile] ; break;
	case 1 : if(!playing && soundLength)
	    {
	    offset = (int)([sliders floatValue]*soundLength);
	    startPlay = samples + offset;
	    if(soundLength-offset <= 0) return self;
	    [self soundInit];
	    k_err = snddriver_stream_start_writing(
	    write_port,startPlay,soundLength-offset,0,
					 	0,0,0,1,0,0,0,0,reply_port);
	    iter = DPSAddTimedEntry(.1,iterate,self,NX_BASETHRESHOLD);
	    }
	    playing = 1 ; break ;
	case 2 : if(playing)
	    {
		DPSRemoveTimedEntry(iter);
		k_err = SNDRelease(SND_ACCESS_OUT|SND_ACCESS_DSP,
			dev_port,owner_port);
		Error(k_err,"Releasing ");
	    }
	    playing = 0; break;
	case 3 : config = SNDDRIVER_STREAM_THROUGH_DSP_TO_SNDOUT_44; 
	    [self sliderChange:sliders]; break ;
	case 4 : config = SNDDRIVER_STREAM_TO_SNDOUT_44; 
	    [self sliderChange:sliders]; break ;
	case 5 : config = SNDDRIVER_STREAM_TO_SNDOUT_22; 
	    [self sliderChange:sliders]; break ;
    }
    return self;
}

- close
{
    SNDRelease(SND_ACCESS_OUT|SND_ACCESS_DSP,dev_port,owner_port);
    [displayView close];
    [warningPanel close];
    if(playing) DPSRemoveTimedEntry(iter);
    playing = 0;
    return self;
}

- soundInit
{
kern_return_t k_err=0;
int protocol;

    dev_port = owner_port = 0;
    k_err = SNDAcquire(SND_ACCESS_OUT|SND_ACCESS_DSP,0,0,0,
    	NULL_NEGOTIATION_FUN,0,&dev_port,&owner_port);
    Error(k_err,"SNDAcquire ");    
    k_err += snddriver_get_dsp_cmd_port(dev_port,owner_port,&cmd_port);
    protocol = SNDDRIVER_DSP_PROTO_RAW;
    k_err += snddriver_stream_setup(dev_port, owner_port,config,
				 DMASIZE, 2, 
				 128*1024, 512*1024,
				 &protocol, &write_port);
    k_err += snddriver_dsp_protocol(dev_port, owner_port, protocol);
    k_err += SNDBootDSP(dev_port, owner_port, Effect);
    playing = 0;
    return self;
}

- openFile
{
static int firstTime = 1;
const char *extension[2];

    extension[0] = "snd";
    extension[1] = NULL;
    if(firstTime) 
    [openPanel runModalForDirectory:NXHomeDirectory() file:"" types:extension];
    else [openPanel runModalForTypes:extension];
    [warningPanel close];
    firstTime = 0;   
    return self;
}

- (BOOL) validateFilename:aPanel 
{
int k_err,i;
const char *filetmp;
char title[50];

    filetmp = [aPanel filename];
    k_err = SNDReadSoundfile((char*)filetmp, &soundFile);
    if(k_err || soundFile->dataFormat != SND_FORMAT_LINEAR_16)
    {
	[warningPanel makeKeyAndOrderFront:self];
	return NO;
    }
    soundFileName = filetmp;
    k_err = SNDGetDataPointer(soundFile,(char**)&samples,&soundLength,&i);
    Error(k_err,"Data Pointer");
    strcpy(title,"Slow Play Current Sound File: ");
    strcat(title,strrchr(soundFileName,'/')+1);
    [displayView setTitle:title];
    [[button findCellWithTag:1] setEnabled:YES];
    [[button findCellWithTag:2] setEnabled:YES];
    return YES;
}

- checkTime
{
int sampleCount,k_err;

    k_err = snddriver_stream_nsamples(write_port,&sampleCount);
    [sliders setFloatValue:(float)(sampleCount+2*offset)/soundLength/2];
    k_err = msg_receive(reply_msg, RCV_TIMEOUT, 10);
    if(!k_err) 
    {
	DPSRemoveTimedEntry(iter);
	SNDRelease(SND_ACCESS_OUT|SND_ACCESS_DSP,dev_port,owner_port);
	playing = 0;
    }
    return self;
}

- sliderChange:sender
{
    if(!playing) return self;
    DPSRemoveTimedEntry(iter);
    SNDRelease(SND_ACCESS_OUT|SND_ACCESS_DSP,dev_port,owner_port);
    playing = 0;
    [button selectCellWithTag:1];
    [self buttonPush:button];
    return self;
}

@end
