#import "MiscSoundTracker.h"
#import <stdio.h>

@implementation MiscSoundTracker

// KNOWN BUGS:  NeXT's sound object does not release sampling rate information
// properly.  Hence, the tracker cannot get seconds information correctly,
// when recording, and so must rely on a preset default for its sampling
// rate in returning seconds.

// also, samples do not keep up with pausing.



// timed entry procedure for periodically updating

DPSTimedEntryProc SOUNDTRACKER_update_tracker
	(DPSTimedEntry teNum,double now, void* the_tracker)
	{
	MiscSoundTracker* temp_tracker=(MiscSoundTracker*) the_tracker;
	[temp_tracker update];
	return (void*) NULL;
	}




- init
	{
	[super init];
	running=NO;
	default_sampling_rate=SOUNDTRACKER_DEFAULT_SAMPLING_RATE;
	send_type=SOUNDTRACKER_SEND_TYPE_SAMPLES;
	refresh=SOUNDTRACKER_TIMED_ENTRY_SPEED;
	teNum=0;
	//printf ("Init\n");
	return self;
	}

- awake
	{
	[super awake];
	teNum=0;
	//printf ("Awake\n");
	return self;
	}


- update
	{
	//printf("Updating\n");
	if (target!=NULL)
		{
		//printf ("Target Not Null\n");
		if (send_type==SOUNDTRACKER_SEND_TYPE_SAMPLES||
			send_type==SOUNDTRACKER_SEND_TYPE_MUTE||
			send_type==SOUNDTRACKER_SEND_TYPE_DEEMPHASIS)
			{
			//printf ("Sending Take Message\n");
			if (![target respondsTo:@selector(takeIntValueFrom:)])
				 return NULL;
			[target takeIntValueFrom:self];
			}
		else if (send_type==SOUNDTRACKER_SEND_TYPE_RATIO||
				send_type==SOUNDTRACKER_SEND_TYPE_PERCENT)
			{
			int status=[sound status];
			if (status==NX_SoundRecording||
				status==NX_SoundRecordingPaused)
				{
				[self clearTarget];
				}
			else
				{
				if (![target respondsTo:@selector(takeFloatValueFrom:)])
					return NULL;
				[target takeFloatValueFrom:self];
				}
			}
		else if (send_type==SOUNDTRACKER_SEND_TYPE_SECONDS||
				send_type==SOUNDTRACKER_SEND_TYPE_LEFT||
				send_type==SOUNDTRACKER_SEND_TYPE_RIGHT||
				send_type==SOUNDTRACKER_SEND_TYPE_MONO)
			{
			if (![target respondsTo:@selector(takeFloatValueFrom:)])
				 return NULL;
			[target takeFloatValueFrom:self];
			}
		else printf ("SOUNDTRACKER Error:  No Send Type\n");
		}
	return self;
	}


- setRefresh:(float) number_seconds
	{
	if (number_seconds>0)
		{
		refresh=number_seconds;
		if (teNum) 
			{
			DPSRemoveTimedEntry(teNum);
			teNum=DPSAddTimedEntry(refresh, 
				(DPSTimedEntryProc) SOUNDTRACKER_update_tracker,
				(void*) self, (int) NX_RUNMODALTHRESHOLD);
			}
		}
	return self;
	}
	
- free
	{
	if (output_device!=NULL) [output_device free];
	return [super free];
	}


- setSound:this_sound_or_soundview
	{
	sound=this_sound_or_soundview;
	return self;
	}


- sound
	{
	return sound;
	}

- setDefaultSamplingRate:(float) this_rate
	{
	if (this_rate!=0.0) default_sampling_rate=this_rate;
	return self;
	}
	
- setTarget:this_target
	{
	target=this_target;
	return self;
	}


- target
	{
	return target;
	}


- run
	{
	running=YES;
	if (!teNum) teNum=DPSAddTimedEntry(refresh, 
			(DPSTimedEntryProc) SOUNDTRACKER_update_tracker,
			(void*) self, (int) NX_RUNMODALTHRESHOLD);
	return self;
	}


- stop
	{
	running=NO;
	if (teNum) DPSRemoveTimedEntry(teNum);
	teNum=0;
	return self;
	}


- sendSamples
	{
	send_type=SOUNDTRACKER_SEND_TYPE_SAMPLES;
	return self;
	}


- sendSeconds
	{
	send_type=SOUNDTRACKER_SEND_TYPE_SECONDS;
	return self;
	}


- sendRatio
	{
	send_type=SOUNDTRACKER_SEND_TYPE_RATIO;
	return self;
	}
	
- sendPercent
	{
	send_type=SOUNDTRACKER_SEND_TYPE_PERCENT;
	return self;
	}
	
- sendLeft
	{
	send_type=SOUNDTRACKER_SEND_TYPE_LEFT;
	return self;
	}
	

- sendRight
	{
	send_type=SOUNDTRACKER_SEND_TYPE_RIGHT;
	return self;
	}
	

- sendMono
	{
	send_type=SOUNDTRACKER_SEND_TYPE_MONO;
	return self;
	}
	

- sendMute
	{
	send_type=SOUNDTRACKER_SEND_TYPE_MUTE;
	return self;
	}
	
- sendDeemphasis
	{
	send_type=SOUNDTRACKER_SEND_TYPE_DEEMPHASIS;
	return self;
	}

- sendLeftPeak
	{
	send_type=SOUNDTRACKER_SEND_TYPE_LEFT_PEAK;
	return self;
	}

- sendRightPeak
	{
	send_type=SOUNDTRACKER_SEND_TYPE_RIGHT_PEAK;
	return self;
	}
	
- sendMonoPeak
	{
	send_type=SOUNDTRACKER_SEND_TYPE_MONO_PEAK;
	return self;
	}

- (float) floatValue	
	{
	if (send_type==SOUNDTRACKER_SEND_TYPE_SECONDS)
		{
		if (sound!=NULL)
			{
			if ([sound isKindOf:[Sound class]])
				{
				float n=[sound samplingRate];
				//printf ("%f\n",n);
				if (n==0.0) n=default_sampling_rate;
				return ((float)[sound samplesProcessed])/n;
				}
			else if ([sound isKindOf:[SoundView class]])
				{
				id snd1=[sound soundBeingProcessed];
				float n=[snd1 samplingRate];
				//printf ("%f\n",n);
				if (n==0.0) n=default_sampling_rate;
				return ((float)[snd1 samplesProcessed])/n;
				}
			}
		}
	else if (send_type==SOUNDTRACKER_SEND_TYPE_RATIO)
		{
		if (sound!=NULL)
			{
			if ([sound isKindOf:[Sound class]])
				{
				//int status=[sound status];  // no use right now
									
				return ((float)[sound samplesProcessed])/
					((float)[sound sampleCount]);
				}
			else if ([sound isKindOf:[SoundView class]])
				{
				id snd1=[sound soundBeingProcessed];
				//int status=[snd1 status];  // no use right now
					
				return ((float)[snd1 samplesProcessed])/
					((float)[snd1 sampleCount]);
				}
			}
		}
	else if (send_type==SOUNDTRACKER_SEND_TYPE_PERCENT)
		{
		if (sound!=NULL)
			{
			if ([sound isKindOf:[Sound class]])
				{
				//int status=[sound status];  // no use right now
									
				return ((float)[sound samplesProcessed])/
					((float)[sound sampleCount])*100;
				}
			else if ([sound isKindOf:[SoundView class]])
				{
				id snd1=[sound soundBeingProcessed];
				//int status=[snd1 status];  // no use right now
					
				return ((float)[snd1 samplesProcessed])/
					((float)[snd1 sampleCount])*100;
				}
			}
		}
	else if (send_type==SOUNDTRACKER_SEND_TYPE_LEFT)
		{
		float l,r;
		[Sound getVolume:&l:&r];
		return l;
		}
	else if (send_type==SOUNDTRACKER_SEND_TYPE_RIGHT)
		{
		float l,r;
		[Sound getVolume:&l:&r];
		return r;
		}
	else if (send_type==SOUNDTRACKER_SEND_TYPE_MONO)
		{
		float l,r;
		[Sound getVolume:&l:&r];
		return (l+r)/2.0;
		}
	else if (send_type==SOUNDTRACKER_SEND_TYPE_LEFT_PEAK)
		{
		float l,r;
		
		// try to grab resources
		if (output_device==NULL) output_device=[[NXSoundOut alloc] init];
		
		if (output_device!=NULL)
			{
			[output_device getPeakLeft:&l right:&r];
			return l;
			}
		// else...return -1.0 as shown below
		}
	else if (send_type==SOUNDTRACKER_SEND_TYPE_RIGHT_PEAK)
		{
		float l,r;
		
		// try to grab resources
		if (output_device==NULL) output_device=[[NXSoundOut alloc] init];
		
		if (output_device!=NULL)
			{
			[output_device getPeakLeft:&l right:&r];
			return r;
			}
		// else...return -1.0 as shown below
		}
	else if (send_type==SOUNDTRACKER_SEND_TYPE_MONO_PEAK)
		{
		float l,r;
		
		// try to grab resources
		if (output_device==NULL) output_device=[[NXSoundOut alloc] init];
		
		if (output_device!=NULL)
			{
			[output_device getPeakLeft:&l right:&r];
			return (l+r)/2.0;
			}
		// else...return -1.0 as shown below
		}

	else printf ("SOUNDTRACKER Error:  Wrong send type for floatValue\n");
	return -1.0;
	}


- (int) intValue	
	{
	//printf ("Okay\n");
	if (send_type==SOUNDTRACKER_SEND_TYPE_SAMPLES)
		{
		if (sound!=NULL)
			{
			if ([sound isKindOf:[Sound class]])
				{
				return [sound samplesProcessed];
				}
			else if ([sound isKindOf:[SoundView class]])
				{
				id snd1=[sound soundBeingProcessed];
				return [snd1 samplesProcessed];
				}
			}
		}
	else if (send_type==SOUNDTRACKER_SEND_TYPE_MUTE)
		{
		return (int) [Sound isMuted];
		}
	else if (send_type==SOUNDTRACKER_SEND_TYPE_DEEMPHASIS)
		{
		// try to grab resources
		if (output_device==NULL) output_device=[[NXSoundOut alloc] init];
		
		if (output_device!=NULL)
			{
			return (int) [output_device doesDeemphasize];
			}
		else return NO;
		}
	else printf ("SOUNDTRACKER Error:  Wrong send type for intValue\n");
	return -1;
	}


- setVolumeTo:sender	
	{
	float l,r,x;
	[Sound getVolume:&l:&r];
	if (! [sender respondsTo:@selector(floatValue)]) return NULL;
	x=[sender floatValue];
	if (x<0||x>1) return NULL;
	if (send_type==SOUNDTRACKER_SEND_TYPE_LEFT) [Sound setVolume:x:r];
	if (send_type==SOUNDTRACKER_SEND_TYPE_RIGHT) [Sound setVolume:l:x];
	if (send_type==SOUNDTRACKER_SEND_TYPE_MONO) [Sound setVolume:x:x];
	return self;
	}


- setMuteTo:sender	
	{
	int x;
	if (! [sender respondsTo:@selector(intValue)]) return NULL;
	x=[sender intValue];
	if (x!=0) x=1;
	[Sound setMute:(BOOL)x];
	return self;
	}

- setDeemphasisTo:sender	
	{
	int x;
	if (! [sender respondsTo:@selector(intValue)]) return NULL;
	x=[sender intValue];
	if (x!=0) x=1;
	
	// try to grab resources
	if (output_device==NULL) output_device=[[NXSoundOut alloc] init];
	
	if (output_device!=NULL)
		{
		[output_device setDeemphasis:x];
		}
	return self;
	}


- run:sender
	{
	return [self run];
	}


- stop:sender
	{
	return [self stop];
	}


- sendSamples:sender
	{
	return [self sendSamples];
	}


- sendSeconds:sender
	{
	return [self sendSeconds];
	}


- sendRatio:sender
	{
	return [self sendRatio];
	}

- sendPercent:sender
	{
	return [self sendPercent];
	}

- sendLeft:sender
	{
	return [self sendLeft];
	}

- sendRight:sender
	{
	return [self sendRight];
	}

- sendMono:sender
	{
	return [self sendMono];
	}

- sendMute:sender
	{
	return [self sendMute];
	}
	
- sendDeemphasis:sender
	{
	return [self sendDeemphasis];
	}
	
- sendLeftPeak:sender
	{
	return [self sendLeftPeak];
	}
	
- sendRightPeak:sender
	{
	return [self sendRightPeak];
	}	
	
- sendMonoPeak:sender
	{
	return [self sendMonoPeak];
	}

- read:(NXTypedStream*) stream
	{
	[super read:stream];
	NXReadTypes(stream,"cif", &running,&send_type,&refresh);
	return self;
	}

- write:(NXTypedStream*) stream
	{
	[super write:stream];
	NXWriteTypes(stream,"cif", &running,&send_type,&refresh);
	return self;
	}

- clearTarget
	{
	if ([target respondsTo:@selector(setStringValue:)])
		{
		[target setStringValue:""];
		}
	else [target setIntValue:0];
	return self;
	}

@end