This is EdSoundView.m in view mode; [Download] [Up]
/* EdSoundView.m -- implementation for custom SoundView
*
* jwp@silvertone.Princeton.edu, 11/89
* Version 1.2, 1/90
* -- Added enveloping
* Version 1.21, 2/90
* -- Fixed enveloping for stereo files
* -- Fixed enveloping and erasing to maintain selection
* Version 1.3, 2/90
* -- Fixed bug that allowed enveloping of fragmented files
* Version 1.4, 4/90
* -- Now envelopes edited sounds
* Update for 2.0, 3/91
* -- Delegate method "soundChanged:" is now called "soundDidChange:"
*
*/
#import "EdSoundView.h"
#import <appkit/Panel.h>
#import <soundkit/soundkit.h>
#import <string.h>
/* Prototypes of functions in SNDindirect
*/
extern char *getblock(id aSound, int inskip, int nsamps);
extern int putblock(id aSound, int inskip, int nsamps, char *samples);
/* C functions used by EdSoundView methods:
*/
/* makesilence() -- Make a sound full of silence
* Returns pointer to silent Sound object
*/
id makesilence(modelsnd,nsamps)
id modelsnd; /* Sound we're doing this for */
int nsamps; /* Amount of silence */
{
id newsnd; /* The silent sound */
SNDSoundStruct *s; /* Sound struct for modelsnd */
int nbytes; /* Number of bytes of silence */
unsigned char *dataptr; /* Pointer to samples */
int format; /* Sound's data format */
/* Use the info in modelsnd to determine the data size, etc. of
* the silent Sound
*/
s = [modelsnd soundStruct];
format = [modelsnd dataFormat]; /* don't use struct dataFormat,
* since it might be INDIRECT
*/
nbytes = SNDSamplesToBytes(nsamps,s->channelCount,format);
newsnd = [Sound new];
[newsnd setDataSize:nbytes
dataFormat:format
samplingRate:s->samplingRate
channelCount:s->channelCount
infoSize:[modelsnd infoSize]];
/* Fill the newsnd data space with zeroes and return
*/
dataptr = [newsnd data];
*dataptr = 0;
bcopy(dataptr,dataptr+1,nbytes-1); /* Fill with 0's */
return newsnd;
}
/* = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = */
@implementation EdSoundView
/* erase -- Zero out the current selection
*/
- erase:sender
{
id silent; /* "Sound of silence ..." */
int start,dur; /* Start and dur of selection */
/* Get the duration of the selection and make a sound object with
* that much silence in it.
*/
[self getSelection:&start size:&dur];
silent = makesilence(sound,dur);
/* Write the silence to the pasteboard, then paste into current sound.
*/
[silent writeToPasteboard];
[self paste:self];
[silent free]; /* Free this space */
if (delegate && [delegate respondsTo:@selector(soundDidChange:)])
[delegate perform:@selector(soundDidChange:) with:self];
/* Pasting screws up the selection. Reset it to where we were.
*/
[self setSelection:start size:dur];
return self;
}
/* = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = */
/* addSilence -- add some silence to file
* Argument is duration (in seconds) of silence to add
*/
- addSilence:(float)dur
{
id silent; /* "Sound of silence ..." */
int nsamps;
/* Make a Sound object with 'dur' seconds worth of silence in it.
* Use our current sound as a model for sampling rate, etc.
*/
nsamps = (int)(dur * [sound samplingRate]);
silent = makesilence(sound,nsamps);
/* Write the silence to the pasteboard, then paste into current sound.
*/
[silent writeToPasteboard];
[self paste:self];
[silent free]; /* Free this space */
if (delegate && [delegate respondsTo:@selector(soundDidChange:)])
[delegate perform:@selector(soundDidChange:) with:self];
return self;
}
/* = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = */
#define SNDSHORT SND_FORMAT_LINEAR_16
#define SNDFLOAT SND_FORMAT_FLOAT
/* envelope:Points:
* Envelopes the current selection. See "EnvelopeView.h" for details
* about the envelope format.
*/
- envelope:(NXPoint *)env Points:(int)n
{
id newSound; /* Scratch sound to work on */
int start; /* Starting sample of selection */
int size; /* Number of samples to envelope */
int nchans; /* Number of channels */
int format; /* Format of sound (short/float) */
char *samples; /* Pointer to samples */
short *sout; /* Pointer to short samples */
float *fout; /* Pointer to float samples */
int nsamps; /* Number of samples in envelope segment */
float ampmul, incr; /* Amplitude factor and increment per sample */
int i,j;
/* Make a new sound that contains the current selection:
*/
newSound = [Sound new];
nchans = [sound channelCount];
[self getSelection:&start size:&size];
if (!size) /* No selection = no envelope */
return self;
[newSound copySamples:sound at:start count:size];
/* Get the samples into a contiguous array via getblock().
* (See SNDindirect.m for info on this function)
*/
if (!(samples = getblock(newSound,0,size))) {
fprintf(stderr,"EdSoundView: error in getblock()\n");
return self;
}
format = [newSound dataFormat];
n--;
/* Two versions of same code: one for shorts, one for floats. I could
* just put a test in the inner loop for SNDSHORT/SNDFLOAT, but that
* would slow things down.
*/
if (format == SNDSHORT) {
sout = (short *)samples;
for (i=0; i < n; i++) {
if (!(nsamps = (env[i+1].x - env[i].x) * size))
continue;
ampmul = env[i].y;
incr = (env[i+1].y - env[i].y) / nsamps;
while (nsamps--) {
for (j = 0; j < nchans; j++)
*sout++ *= ampmul;
ampmul += incr;
}
}
}
else if (format == SNDFLOAT) {
fout = (float *)samples;
for (i=0; i < n; i++) {
if (!(nsamps = (env[i+1].x - env[i].x) * size))
continue;
ampmul = env[i].y;
incr = (env[i+1].y - env[i].y) / nsamps;
while (nsamps--) {
for (j = 0; j < nchans; j++)
*fout++ *= ampmul;
ampmul += incr;
}
}
}
/* Put the samples back into newSound and update the sound by making
* a phony paste -- writing directly to the
* sound would force a complete re-draw of the view.
*/
putblock(newSound,0,size,samples);
[newSound writeToPasteboard];
[self paste:self];
/* Pasting screws up the selection. Reset it to where we were so that
* we can apply the same envelope multiple times.
*/
[self setSelection:start size:size];
return self;
}
@end
These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.