This is PCHPlot.m in view mode; [Download] [Up]
/* Generated by Interface Builder */
#import "PCHPlot.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 <appkit/OpenPanel.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 <sound/sound.h>
#import <stdio.h>
#import <streams/streams.h>
#import <dpsclient/wraps.h>
#import "PWfft.h"
#define PITCH 0
#define AMP 1
#define SIZE 2
#define MAXZOOM 4
#define MINZOOM -3
@implementation PCHPlot
extern int errno;
+ new:(const char *)title
{
NXRect aRect;
self = [super new];
// Set up memory
PSops = NULL;
PSAdata = NULL;
PSPdata = NULL;
[NXApp loadNibSection:"pchplot.nib" owner:self];
[myView setDelegate:self];
[myView setParent:self];
[myPlot setDelegate:self];
numBytes = 0;
zoomfactor = 1;
curzoom = 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 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 setPCHfile:filename] < 0) {
hasData = NO;
[myPlot setTitleAsFilename:"Untitled"];
[self show:self];
return self;
}
hasData = YES;
}
[self show:self];
return self;
}
- (int) setPCHfile:(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/(SIZE*(sizeof(float))))-1;
numBytes = st.st_size;
[numFrames setIntValue:frames];
pchData = (float *)malloc(st.st_size);
if (read(openfd, pchData, st.st_size) < 0) {
[self error:"Error reading input file : ":errno];
return -1;
}
return 0;
}
- drawData
{
int i, winwidth;
float yscalea, yscalep, half, zoomsize;
NXRect viewBounds, visBounds, scrollBounds;
NXSize scrollSize;
float amax, amin; // amplitude boundaries
float ptchmax, ptchmin; // pitch boundaries
// DPSUserPath stuff
float bbox[4];
float *t, *a, *ptch; // temporary variables
char *o;
// Only draw plot if such information exists
if (!hasData)
return self;
amax = MINFLOAT; ptchmax = MINFLOAT;
amin = MAXFLOAT; ptchmin = MAXFLOAT;
t = pchData;
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 += SIZE;
}
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;
}
[myView getBounds:&viewBounds];
[myView getVisibleRect:&visBounds];
[myScroll getContentSize:&scrollSize];
[myScroll getDocVisibleRect:&scrollBounds];
[myView getVisibleRect:&visBounds];
scrollBounds.size.width *= zoomfactor;
/* 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));
t = pchData;
for (i = 0, a = PSAdata, ptch = PSPdata, o = PSops;
i < winwidth; i++) {
*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);
*o++ = dps_moveto;
*o++ = dps_rlineto;
t = (pchData) + (SIZE * (int)(i * step));
}
bbox[0] = 0.0;
bbox[1] = 0.0;
bbox[2] = winwidth;
bbox[3] = ((amax - amin)*yscalea) + half;
[myView drawPlot:PSAdata:PSops:bbox:winwidth:NX_BLACK];
bbox[1] = half;
bbox[3] = visBounds.size.height;
[myView drawPlot:PSPdata:PSops:bbox:winwidth:NX_BLACK];
PWdrawruler(0, frames,(20*frames/winwidth), (20*frames/winwidth)/step);
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;
}
- 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;
}
- print:sender
{
[myView printPSCode:sender];
return self;
}
- updateCursor:sender
{
float amp, pitch, *t;
int cursor, width, frame1, frame2, temp;
if (!hasData)
return self;
cursor = [myView getcurPos];
width = [myView getWidth];
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 = pchData + (SIZE * (int)((cursor + width) * step));
amp = t[AMP];
pitch = t[PITCH];
[ampFrame setFloatValue:amp];
[pitchFrame setFloatValue:pitch];
[playFrame1 setIntValue:(frame1 + 1)];
[playFrame2 setIntValue:(frame2 + 1)];
return self;
}
- selectAll:sender
{
[myView changeCurs:0:(frames/step)];
[playFrame1 setIntValue:1];
[playFrame2 setIntValue:(frames+1)];
return self;
}
- cursorSel:sender
{
[myView setCursorType:SELECTION];
return self;
}
- cursorHair:sender
{
[myView setCursorType:HAIRLINE];
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;
}
- changeAmp:sender
{
float *t, val;
int cursor, width, i, frame1, frame2, temp;
cursor = [myView getcurPos];
width = [myView getWidth];
frame1 = (int)cursor * step;
frame2 = (int)(cursor + width) * step;
if (frame1 > frame2) {
temp = frame1;
frame1 = frame2;
frame2 = temp;
}
t = pchData + (SIZE * frame1);
val = [ampFrame floatValue];
[self saveundo:(frame2 - frame1 + 1)*SIZE*sizeof(float):t];
for (i = frame1; i <= frame2; i++) {
t[AMP] = val;
t = (pchData) + (SIZE * (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];
frame1 = (int)cursor * step;
frame2 = (int)(cursor + width) * step;
if (frame1 > frame2) {
temp = frame1;
frame1 = frame2;
frame2 = temp;
}
t = pchData + (SIZE * frame1);
val = [pitchFrame floatValue];
[self saveundo:(frame2 - frame1 + 1)*SIZE*sizeof(float):t];
for (i = frame1; i <= frame2; i++) {
t[PITCH] = val;
t = (pchData) + (SIZE * (i + 1));
}
[myView display];
[self setDirty:YES];
return self;
}
- doCopy:(NXStream *)selection
{
float *t;
int cursor, width, frame1, frame2, temp, bytes;
if (!hasData) {
return self;
}
cursor = [myView getcurPos];
width = [myView getWidth];
frame1 = (int)cursor * step;
frame2 = (int)(cursor + width) * step;
if (frame1 > frame2) {
temp = frame1;
frame1 = frame2;
frame2 = temp;
}
t = pchData + (SIZE * frame1);
bytes = (frame2 - frame1)*SIZE*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];
frame1 = (int)cursor * step;
frame2 = (int)(cursor + width) * step;
if (frame1 > frame2) {
temp = frame1;
frame1 = frame2;
frame2 = temp;
}
t = pchData + (SIZE * frame1);
bytes = (frame2 - frame1)*SIZE*sizeof(float);
NXWrite(selection, t, bytes);
numBytes -= bytes;
frames = (numBytes/(SIZE*sizeof(float)))-1;
[numFrames setIntValue:frames];
v = t + (bytes / sizeof(float));
for (i = 0; i < (bytes / sizeof(float)); i++) {
*t++ = *v++;
}
realloc(pchData, 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;
pchData = (float *)malloc(bytes);
numBytes = bytes;
frames = (numBytes/(SIZE*sizeof(float))) - 1;
[numFrames setIntValue:frames];
t = pchData;
for (i = 0; i < (bytes / sizeof(float)); i++) {
*t++ = *data++;
}
[myView display];
return self;
}
numBytes += bytes;
frames = (numBytes/(SIZE*sizeof(float)))-1;
[numFrames setIntValue:frames];
realloc(pchData, numBytes);
cursor = [myView getcurPos];
frame1 = (int)cursor * step;
size = (numBytes - bytes) - (frame1 * SIZE * sizeof(float));
v = pchData + (numBytes / sizeof(float)) - 1;
t = pchData + ((numBytes - bytes) / sizeof(float)) - 1;
for (i = 0; i < (size / sizeof(float)); i++) {
*v-- = *t--;
}
t = pchData + (SIZE * 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;
}
- multiplyAmp:sender
{
float *t, val;
int cursor, width, i, frame1, frame2, temp;
cursor = [myView getcurPos];
width = [myView getWidth];
frame1 = (int)cursor * step;
frame2 = (int)(cursor + width) * step;
if (frame1 > frame2) {
temp = frame1;
frame1 = frame2;
frame2 = temp;
}
val = [mulAmpFrame floatValue];
t = pchData + (SIZE * frame1);
[self saveundo:(frame2 - frame1 + 1)*SIZE*sizeof(float):t];
for (i = frame1; i <= frame2; i++) {
t[AMP] *= val;
t = (pchData) + (SIZE * (i + 1));
}
[myView display];
[self setDirty:YES];
return self;
}
- multiplyPitch:sender
{
float *t, val, top, bottom;
int cursor, width, i, frame1, frame2, temp;
cursor = [myView getcurPos];
width = [myView getWidth];
t = pchData + (SIZE * (int)(cursor * step));
frame1 = (int)cursor * step;
frame2 = (int)(cursor + width) * step;
if (frame1 > frame2) {
temp = frame1;
frame1 = frame2;
frame2 = temp;
}
val = [mulPitchFrame floatValue];
top = [topPitchFrame floatValue];
bottom = [botPitchFrame floatValue];
t = pchData + (SIZE * frame1);
[self saveundo:(frame2 - frame1 + 1)*SIZE*sizeof(float):t];
for (i = frame1; i <= frame2; i++) {
if (t[PITCH] <= top && t[PITCH] >= bottom)
t[PITCH] *= val;
t = (pchData) + (SIZE * (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];
frame1 = ((int)(cursor * step)) - 1;
frame2 = ((int)((cursor + width) * step)) + 1;
if (frame1 > frame2) {
temp = frame1;
frame1 = frame2;
frame2 = temp;
}
t = pchData + (SIZE * frame1);
v = pchData + (SIZE * frame2);
first = t[PITCH];
last = v[PITCH];
t = pchData + (SIZE * frame1);
scale = (last - first) / (frame2 - frame1);
[self saveundo:(frame2 - frame1 + 1)*SIZE*sizeof(float):t];
for (i = frame1, j = 0; i <= frame2; i++) {
t[PITCH] = first + (j * scale);
t = (pchData) + (SIZE * (i + 1));
++j;
}
[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 *)pchData, 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 *)pchData,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 *)pchData, 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 *)pchData, numBytes) < 0) {
[self error:"Error saving file : ":errno];
return self;
}
[self setDirty:NO];
return self;
}
}
return self;
}
- setOutputFile:sender
{
id openP;
char *types[2];
types[0] = "snd";
types[1] = 0;
openP = [OpenPanel new];
[openP runModalForTypes:types];
if ([openP filenames]) {
strcpy(soundFilename, [openP filename]);
[soundFileFrame setStringValue:soundFilename];
}
return self;
}
- playOutputSound:sender
{
int err;
SNDSoundStruct *s;
strcpy(soundFilename, [soundFileFrame stringValue]);
if (!strlen(soundFilename))
return self;
err = SNDReadSoundfile(soundFilename, &s);
if (!err) {
err = SNDStartPlaying(s, 1, 5, 0, 0,(SNDNotificationFun)SNDFree);
if (!err)
SNDWait(1);
else
[self error:"Error playing soundfile":0];
}
else {
[self error:"Error reading soundfile":0];
}
return self;
}
- play:sender
{
return self;
}
- doPitchAnal:sender
{
char cmd[1024];
strcpy(soundFilename, [soundFileFrame stringValue]);
if (!strlen(soundFilename)) {
strcpy(soundFilename, "/tmp/anal.snd");
[soundFileFrame setStringValue:soundFilename];
}
sprintf(cmd, "%s %s %s %d %d", [NXApp playpitch], filename, soundFilename, [playFrame1 intValue], [playFrame2 intValue]);
system(cmd);
return self;
}
- drawPlot:sender
{
return self;
}
- plot
{
return myPlot;
}
- 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;
}
@end
These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.