ftp.nice.ch/pub/next/audio/apps/LPCView.NIHS.bs.tar.gz#/LPCView/Source/LPCPlot.m

This is LPCPlot.m in view mode; [Download] [Up]

/* Generated by Interface Builder */

#import "LPCPlot.h"
#import "LPCView.h"
#import "Dispatcher.h"
#import <appkit/Application.h>
#import <appkit/Window.h>
#import <appkit/ScrollView.h>
#import <appkit/Panel.h>
#import <appkit/Cell.h>
#import <appkit/SavePanel.h>
#import <strings.h>
#import <sys/types.h>
#import <sys/stat.h>
#import <sys/file.h>
#import <libc.h>
#import <dpsclient/dpsclient.h>
#import <math.h>
#import <dpsclient/wraps.h>
#import "PWfft.h"

/*
 *  Frame information
 */
#define RESIDAMP	0
#define AMP	1
#define THRESH	2
#define PITCH	3

#define MAXZOOM	4
#define MINZOOM	-3

@implementation LPCPlot

extern int errno;

/*
 *  Create a new document to display a LPC plot
 */
+ new:(const char *)title
{
	NXRect aRect;
	
	self = [super new];
	// Set up memory
	PSops = NULL;
	PSAdata = NULL;
	PSPdata = NULL;
	undoData = NULL;
	undoSize = 0;
	[NXApp loadNibSection:"lpcplot.nib" owner:self];
	[myView setDelegate:self];
	[myView setParent:self];
	[myPlot setDelegate:self];
	numBytes = 0;	
	zoomfactor = 1;
	curzoom = 0;
	threshold = 1.0;
	PWinit();
	[self setDirty:NO];
	
	// Set up view dependencies
	
	[myScroll getDocVisibleRect:&aRect];
	[myView setFrame:&aRect];
	[myScroll setDocView:myView];
	[myScroll setHorizScrollerRequired:YES];
	[myScroll setVertScrollerRequired:NO];
	
	// Set the number of poles for the LPC file - get default from NXApp
	[self setPoles:[NXApp poles]];		
	[numPoles setIntValue:poles];
	
	// Set the title of the window - filename or Untitled 
	strcpy(filename, title);
	if (!strcmp(filename, "Untitled")) {
		hasData = NO;
		[myPlot setTitleAsFilename:"Untitled"];
		[self show:self];
		return self;
	}
	else {
		[myPlot setTitleAsFilename:filename];
		if ([self setLPCfile:filename] < 0) {
			hasData = NO;
			[myPlot setTitleAsFilename:"Untitled"];
			[self show:self];
			return self;
		}
		hasData = YES;
	}
	[self show:self];
	return self;
}

- (int) setLPCfile:(const char *)file
{
	struct stat st;
	
	openfd = open(file, O_RDWR, 0);
	if (openfd < 0) {
		[self error:"Could not open input file : ":errno];
		return -1;
	}
	fstat(openfd, &st);
	frames = (st.st_size/(([self getPoles] + 4)*4))-1;
	numBytes = st.st_size;
	[numFrames setIntValue:frames];
	lpcData = (float *)malloc(st.st_size);
	if (read(openfd, lpcData, st.st_size) < 0) {
		[self error:"Error reading input file : ":errno];
		return -1;
	}
	return 0;	
}

- drawData
{
	int 	i, winwidth, abovethresh, belowthresh;
	float 	yscalea, yscalep, half, zoomsize;
	NXRect 	viewBounds, scrollBounds, visBounds;
	float	amax, amin;	// amplitude boundaries
	float	ptchmax, ptchmin;	// pitch boundaries 
	// DPSUserPath stuff
	float	bbox[4];	
	float	*t, *a, *ptch;	// temporary variables
	float	*pitchT, *ampT;
	char	*o;
	
	//  Only draw plot if such information exists
	if (!hasData) 
		return self;
		
	framesize = ([self getPoles] + 4);
	amax = MINFLOAT;  ptchmax = MINFLOAT;
	amin = MAXFLOAT;  ptchmin = MAXFLOAT;
	
	t = lpcData;
	for (i = 0; i < frames; i++) {
		if (t[AMP] > amax) 
			amax = t[AMP];
		if (t[AMP] < amin)
			amin = t[AMP];
		if (t[PITCH] > ptchmax)
			ptchmax = t[PITCH];
		if (t[PITCH] < ptchmin)
			ptchmin = t[PITCH];
		t += framesize;
	}
	if (amax == amin) {
		if (amax > 0)
			amin = 0;
		else if (amax == 0)
			amin = -1;
		else 
			amin = 2*amax;
	}
	if (ptchmax == ptchmin) {
		if (ptchmax > 0)
			ptchmin = 0;
		else if (ptchmax == 0)
			ptchmin = -1;
		else
			ptchmin = 2*ptchmax;
	}
	[myScroll getDocVisibleRect:&scrollBounds];
	[myView getVisibleRect:&visBounds];
	scrollBounds.size.width *= zoomfactor;
	printf("width = %f\n", scrollBounds.size.width);
	/* Bug in DSPUserpath makes drawing at > 4096 bomb */
	while (scrollBounds.size.width > 4096.0) {
		// Simulate a zoom out
		scrollBounds.size.width /= zoomfactor;
		--curzoom;
		zoomfactor /= 1.5;
		scrollBounds.size.width *= zoomfactor;
		printf("too big -- new width = %f\n", scrollBounds.size.width);
	}
	[myView sizeTo:scrollBounds.size.width :scrollBounds.size.height];
	[myView getBounds:&viewBounds];
	[myView lockFocus];
	PSsetgray(NX_WHITE);
	NXRectFill(&viewBounds);
	[myView unlockFocus];
	winwidth = scrollBounds.size.width;
	zoomsize = frames;
	step = 1.0*zoomsize/winwidth;
	half = 1.0*(visBounds.size.height)/2.0;
	yscalea = 1.0*(half - 25.0)/(1.0*(amax - amin));
	yscalep = 1.0*(half - 25.0)/(1.0*(ptchmax - ptchmin));

	if (!PSAdata) PSAdata = (float *)malloc(4*winwidth*sizeof(float));
	if (!PSPdata) PSPdata = (float *)malloc(4*winwidth*sizeof(float));
	if (!PSops) PSops = (char *)malloc(2*winwidth*sizeof(char));

	pitchT = PSPdata + ((4*winwidth) - 1);
	ampT = PSAdata + ((4*winwidth) - 1);
	
	t = lpcData;
	belowthresh = 0;
	abovethresh = 0;
	for (i = 0, a = PSAdata, ptch = PSPdata, o = PSops; 
		i < winwidth; i++) {
		if (t[THRESH] < threshold) {
			*a++ = i;
			*a++ = 20.0;
			*a++ = 0.0;
			*a++ = ((t[AMP] - amin)*yscalea);

			*ptch++ = i;	
			*ptch++ = half+20.0;
			*ptch++ = 0.0;
			*ptch++ = ((t[PITCH] - ptchmin)*yscalep);
			belowthresh++;
		}
		else {
			*ampT-- = ((t[AMP] - amin)*yscalea);
			*ampT-- = 20.0;
			*ampT-- = 0.0;
			*ampT-- = i;
			
			*pitchT-- = ((t[PITCH] - ptchmin)*yscalep);
			*pitchT-- = 0.0;
			*pitchT-- = half+20.0;
			*pitchT-- = i;
			abovethresh++;
		}
		*o++ = dps_moveto;
		*o++ = dps_rlineto;

		t = (lpcData) + (framesize * (int)(i * step));
	}
	ampT++;
	pitchT++;
	bbox[0] = 0.0;
	bbox[1] = 0.0;
	bbox[2] = winwidth;
	bbox[3] = ((amax - amin)*yscalea) + half;
	[myView drawPlot:PSAdata:PSops:bbox:belowthresh:NX_BLACK];
	[myView drawPlot:ampT:PSops:bbox:abovethresh:NX_DKGRAY];
	bbox[1] = half;
	bbox[3] = visBounds.size.height;
	[myView drawPlot:PSPdata:PSops:bbox:belowthresh:NX_BLACK];
	[myView drawPlot:pitchT:PSops:bbox:abovethresh:NX_DKGRAY];
	[myView lockFocus];
	PWdrawruler(0, frames,(20*frames/winwidth), (20*frames/winwidth)/step);
	[myView unlockFocus];
	if (PSAdata) free(PSAdata);
	if (PSPdata) free(PSPdata);
	if (PSops) free(PSops);
	PSAdata = NULL;
	PSPdata = NULL;
	PSops = NULL;
	return self;
}

- show:sender
{
	[myPlot makeKeyAndOrderFront:self];
	[myView display];
	return self;
}

- setPoles:(int)pole
{
	poles = pole;
	return self;
}

- (int)getPoles
{
	return poles;
}


- updateCursor:sender
{
	float	amp, pitch, *t;
	int	cursor, width, frame1, frame2, temp;
	
	if (!hasData) 
		return self;
	cursor = [myView getcurPos];
	width = [myView getWidth];
	framesize = [self getPoles] + 4;

	frame1 = (int)(cursor * step);
	frame2 = (int)((cursor + width) * step);
	if (frame1 > frame2) {
		temp = frame1;
		frame1 = frame2;
		frame2 = temp;
	}
	[startFrame setIntValue:frame1];
	[endFrame setIntValue:frame2];
	t = lpcData + (framesize * (int)((cursor + width) * step));
	amp = t[AMP];
	pitch = t[PITCH];
	[ampFrame setFloatValue:amp];
	[pitchFrame setFloatValue:pitch];
	return self;
}

- changeCursor:sender
{
	int	frame1, frame2, temp;
	float	loc, loc2, width;
	
	frame1 = [startFrame intValue];
	frame2 = [endFrame intValue];

	frame1 = (frame1 < 0) ? 0 : frame1;
	frame1 = (frame1 > frames) ? frames : frame1;
	frame2 = (frame2 < 0) ? 0 : frame2;
	frame2 = (frame2 > frames) ? frames : frame2;

	if (frame1 > frame2) {
		temp = frame1;
		frame1 = frame2;
		frame2 = temp;
	}
	
	loc = frame1 / step;
	loc2 = frame2 / step;
	width = loc2 - loc;
	[myView changeCurs:loc:width];
	return self;
}

- selectAll:sender
{
	[myView changeCurs:0:(frames/step)];
	return self;
}


- changeAmp:sender
{
	float	*t, val;
	int	cursor, width, i, frame1, frame2, temp;
	
	cursor = [myView getcurPos];
	width = [myView getWidth];
	framesize = [self getPoles] + 4;
	//t = lpcData + (framesize * (int)(cursor * step));
	frame1 = (int)cursor * step;
	frame2 = (int)(cursor + width) * step;
	if (frame1 > frame2) {
		temp = frame1;
		frame1 = frame2;
		frame2 = temp;
	}
	t = lpcData + (framesize * frame1);
	val = [ampFrame floatValue];
	[self saveundo:(frame2 - frame1 + 1)*framesize*sizeof(float):t];
	for (i = frame1; i <= frame2; i++) {
		t[AMP] = val;
		t[RESIDAMP] = val;
		t = (lpcData) + (framesize * (i + 1));
	}
	[myView display];
	[self setDirty:YES];
	return self;		
}

- changePitch:sender
{
	float	*t, val;
	int	cursor, width, i, frame1, frame2, temp;
	
	cursor = [myView getcurPos];
	width = [myView getWidth];
	framesize = [self getPoles] + 4;
	//t = lpcData + (framesize * (int)(cursor * step));
	frame1 = (int)cursor * step;
	frame2 = (int)(cursor + width) * step;
	if (frame1 > frame2) {
		temp = frame1;
		frame1 = frame2;
		frame2 = temp;
	}
	t = lpcData + (framesize * frame1);
	val = [pitchFrame floatValue];
	[self saveundo:(frame2 - frame1 + 1)*framesize*sizeof(float):t];
	for (i = frame1; i <= frame2; i++) {
		t[PITCH] = val;
		t = (lpcData) + (framesize * (i + 1));
	}
	[myView display];
	[self setDirty:YES];
	return self;
}

- multiplyAmp:sender
{
	float	*t, val;
	int	cursor, width, i, frame1, frame2, temp;
	
	cursor = [myView getcurPos];
	width = [myView getWidth];
	framesize = [self getPoles] + 4;
	//t = lpcData + (framesize * (int)(cursor * step));
	frame1 = (int)cursor * step;
	frame2 = (int)(cursor + width) * step;
	if (frame1 > frame2) {
		temp = frame1;
		frame1 = frame2;
		frame2 = temp;
	}
	val = [mulAmpFrame floatValue];
	t = lpcData + (framesize * frame1);
	[self saveundo:(frame2 - frame1 + 1)*framesize*sizeof(float):t];
	for (i = frame1; i <= frame2; i++) {
		t[AMP] *= val;
		t[RESIDAMP] *= val;
		t = (lpcData) + (framesize * (i + 1));
	}
	[myView display];
	return self;
}

- multiplyPitch:sender
{
	float	*t, val, top, bottom;
	int	cursor, width, i, frame1, frame2, temp;
	
	cursor = [myView getcurPos];
	width = [myView getWidth];
	framesize = [self getPoles] + 4;
	//t = lpcData + (framesize * (int)(cursor * step));
	frame1 = (int)cursor * step;
	frame2 = (int)(cursor + width) * step;
	if (frame1 > frame2) {
		temp = frame1;
		frame1 = frame2;
		frame2 = temp;
	}
	t = lpcData + (framesize * frame1);
	val = [mulPitchFrame floatValue];
	top = [topPitchFrame floatValue];
	bottom = [botPitchFrame floatValue];
	[self saveundo:(frame2 - frame1 + 1)*framesize*sizeof(float):t];
	for (i = frame1; i <= frame2; i++) {
		if (t[PITCH] <= top && t[PITCH] >= bottom)
			t[PITCH] *= val;
		t = (lpcData) + (framesize * (i + 1));
	}
	[myView display];
	[self setDirty:YES];
	return self;
}

- interpolate:sender
{
	float	*t, *v, first, last, scale;
	int	cursor, width, i, frame1, frame2, temp, j;
	
	cursor = [myView getcurPos];
	width = [myView getWidth];
	framesize = [self getPoles] + 4;
	frame1 = ((int)(cursor * step)) - 1;
	frame2 = ((int)((cursor + width) * step)) + 1;
	if (frame1 > frame2) {
		temp = frame1;
		frame1 = frame2;
		frame2 = temp;
	}
	t = lpcData + (framesize * frame1);
	v = lpcData + (framesize * frame2);
	first = t[PITCH];
	last = v[PITCH]; 
	//t = lpcData + (framesize * (int)(cursor * step));
	t = lpcData + (framesize * frame1);
	scale = (last - first) / (frame2 - frame1);
	[self saveundo:(frame2 - frame1 + 1)*framesize*sizeof(float):t];
	for (i = frame1, j = 0; i <= frame2; i++) {
		t[PITCH] = first + (j * scale);
		t = (lpcData) + (framesize * (i + 1));
		++j;
	}
	[myView display];
	[self setDirty:YES];
	return self;
}
 
- addError:sender
{
	float	*t, val;
	int	cursor, width, i, frame1, frame2, temp;
	
	cursor = [myView getcurPos];
	width = [myView getWidth];
	framesize = [self getPoles] + 4;
	//t = lpcData + (framesize * (int)(cursor * step));
	frame1 = (int)cursor * step;
	frame2 = (int)(cursor + width) * step;
	if (frame1 > frame2) {
		temp = frame1;
		frame1 = frame2;
		frame2 = temp;
	}
	t = lpcData + (framesize * frame1);
	val = [addErrFrame floatValue];
	[self saveundo:(frame2 - frame1 + 1)*framesize*sizeof(float):t];
	for (i = frame1; i <= frame2; i++) {
		t[THRESH] += val;
		t = (lpcData) + (framesize * (i + 1));
	}
	[myView display];
	[self setDirty:YES];
	return self;	
}

- save:sender
{
	id	sPanel;
	
	sPanel = [SavePanel new];
	if (!strcmp("Untitled", filename)) {
		if ([sPanel runModal]) {
			strcpy(filename, [sPanel filename]);
			[myPlot setTitleAsFilename:filename];
			openfd = open(filename, O_RDWR|O_CREAT, 0644);
			if (openfd < 0) {
				[self error:"Error opening input file : ":errno];
				return self;
			}
			if (write(openfd, (char *)lpcData, numBytes) < 0) {
				[self error:"Error writing file : ":errno];
				return self;
			};
			[self setDirty:NO];
			return self;
		}
	} 
	else {
		lseek(openfd, 0, 0);  // start of file
		if (write(openfd,(char *)lpcData,numBytes) < 0) {
			[self error:"Error writing file : ":errno];
			return self;
		}
		[self setDirty:NO];
		return self;
	}
	return self;
}

- saveAs:sender
{
	id	sPanel;
	char	dir[1024],  *file;
	
	sPanel = [SavePanel new];
	file = rindex(filename, '/') + 1;
	strncpy(dir, filename, (int)(file - filename));
	if ([sPanel runModalForDirectory:dir file:file]) {
		if (strcmp(filename, [sPanel filename])) {
			strcpy(filename, [sPanel filename]);
			close(openfd);
			openfd = open(filename, O_RDWR|O_CREAT, 0644);
			if (openfd < 0) {
				[self error:"Error saving file : ":errno];
				return self;
			}
			if (write(openfd, (char *)lpcData, numBytes) < 0) {
				[self error:"Error saving file : ":errno];
				return self;
			}
			[myPlot setTitleAsFilename:filename];
			[self setDirty:NO];
			return self;
		}
		else {
			lseek(openfd, 0, 0);
			if (write(openfd, (char *)lpcData, numBytes) < 0) {
				[self error:"Error saving file : ":errno];
				return self;
			}
			[self setDirty:NO];
			return self;
		}
	}
	return self;
}

- print:sender
{
	[myView printPSCode:self];
	return self;
}

- plot
{
	return myPlot;
}

- zoomIn:sender
{
	NXRect foo;
	
	if (curzoom >= MAXZOOM) 
		return self;
	[myView getBounds:&foo];
	if ((foo.size.width * 1.5) > 4096.0)
		return self;
	++curzoom;
	zoomfactor *= 1.5;
	[myView display];	
	return self;
}

- zoomOut:sender
{
	if (curzoom <= MINZOOM)
		return self;
	--curzoom;
	zoomfactor /= 1.5;
	[myView display];
	return self;
}

- setThreshold:sender
{
	threshold = [threshFrame floatValue];
	[myView display];
	return self;
}

- doCopy:(NXStream *)selection
{
	float	*t;
	int	cursor, width, frame1, frame2, temp, bytes;
	
	if (!hasData) {
		return self;
	}
	cursor = [myView getcurPos];
	width = [myView getWidth];
	framesize = [self getPoles] + 4;
	//t = lpcData + (framesize * (int)(cursor * step));
	frame1 = (int)cursor * step;
	frame2 = (int)(cursor + width) * step;
	if (frame1 > frame2) {
		temp = frame1;
		frame1 = frame2;
		frame2 = temp;
	}
	t = lpcData + (framesize * frame1);
	bytes =  (frame2 - frame1)*framesize*sizeof(float);
	NXWrite(selection, t, bytes);
	return self;
	
}

- doCut:(NXStream *)selection
{
	float	*t, *v;
	int	cursor, width, i, frame1, frame2, temp, bytes;

	if (!hasData) {
		return self;
	}
	cursor = [myView getcurPos];
	width = [myView getWidth];
	framesize = [self getPoles] + 4;
	//t = lpcData + (framesize * (int)(cursor * step));
	frame1 = (int)cursor * step;
	frame2 = (int)(cursor + width) * step;
	if (frame1 > frame2) {
		temp = frame1;
		frame1 = frame2;
		frame2 = temp;
	}
	t = lpcData + (framesize * frame1);
	bytes =  (frame2 - frame1)*framesize*sizeof(float);
	NXWrite(selection, t, bytes);
	numBytes -= bytes;
	frames = (numBytes/(([self getPoles] + 4)*4))-1;
	[numFrames setIntValue:frames];
	v = t + (bytes / sizeof(float));
	for (i = 0; i < (bytes / sizeof(float)); i++) {
		*t++ = *v++;
	}
	realloc(lpcData, numBytes);
	[myView display];
	[self setDirty:YES];
	return self;
	
}

- doInsert:(float *)data :(int) bytes
{
	int	cursor, frame1, size, i;
	float	*t, *v;
	
	if (!hasData) {
		hasData = 1;
		lpcData = (float *)malloc(bytes);
		numBytes = bytes;
		frames = (numBytes/(([self getPoles] + 4)*4)) - 1;
		[numFrames setIntValue:frames];
		t = lpcData;
		for (i = 0; i < (bytes / sizeof(float)); i++) {
			*t++ = *data++;
		}
		[myView display];
		return self;
	}
	numBytes += bytes;
	frames = (numBytes/(([self getPoles] + 4)*4))-1;
	[numFrames setIntValue:frames];
	realloc(lpcData, numBytes);
	cursor = [myView getcurPos];
	frame1 = (int)cursor * step;
	framesize = [self getPoles] + 4;
	size = (numBytes - bytes) - (frame1 * framesize * sizeof(float));

	v = lpcData + (numBytes / sizeof(float)) - 1;
	t = lpcData + ((numBytes - bytes) / sizeof(float)) - 1;
	for (i = 0; i < (size / sizeof(float)); i++) {
		*v-- = *t--;
	}
	t = lpcData + (framesize * frame1);
	for (i = 0; i < (bytes / sizeof(float)); i++) {
		*t++ = *data++;
	}
	[myView display];
	[self setDirty:YES];
	return self;
}

- saveundo:(int)size: (float *)data
{
	int	i;
	float	*t, *s;
	
	if (undoData) 
		free(undoData);
	undoData = (float *)malloc(size);
	undoLoc = data;
	undoSize = size;
	t = undoData;
	s = data;
	for (i = 0; i < (undoSize / 4); i++) {
		*t++ = *s++;
	}
	return self;
}

- undo:sender
{
	float	*t, *s;
	int	i;
	
	t = undoLoc;
	s = undoData;
	for (i = 0; i < (undoSize / 4); i++) {
		*t++ = *s++;
	}
	[myView display];
	return self;
}

- error:(char *)msg:(int)num
{
	if (num)
		NXRunAlertPanel("Alert", "%s : %s", "OK", NULL, NULL, msg, strerror(num));
	else
		NXRunAlertPanel("Alert", "%s", "OK", NULL, NULL, msg);
	return self;
}

- windowWillClose:sender
{
	if ([myPlot isDocEdited]) {
		switch (NXRunAlertPanel("Alert", "Plot has been edited.  Do you want to save?", "Yes", "No", "Cancel")) {
			case NX_ALERTDEFAULT :
				[self saveAs:self];
				break;
			case NX_ALERTOTHER :
				return nil;
				break;
			default :
				break;
		}
	}
	return self;
}

- setDirty:(BOOL)val
{
	[myPlot setDocEdited:val];
	dirty = val;
	return self;
}

- (BOOL)isDirty
{
	return dirty;
}

- cursorSel:sender
{
	[myView setCursorType:SELECTION];
	return self;
}

- cursorHair:sender
{
	[myView setCursorType:HAIRLINE];
	return self;
}

@end
















These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.