This is MLPluckAlgorithm.m in view mode; [Download] [Up]
#import "MLPluckMaster.h"
#define SAMPLEFREQ 44100
#define MAXEXTRA 8820
#define NEEDED_ZEROES 200
@implementation MLPluckMaster (Algorithm)
- generateTriangle:(double *)buffer length:(int)length
volume:(double)volume maximumAt:(int)maximum
{
// check before calling, to be 0 < maximum < length
int i;
double up, down;
up = volume / maximum;
down = volume / (length - maximum);
i = 0;
while (i < maximum)
*buffer++ = up * i++;
while (i < length)
*buffer++ = down * (length - i++);
return self;
}
- (int)calculateSamples:(short int **)buf
withFrequency:(double)frequency
volume:(double)volume
duration:(double)duration
position:(double)position
attenuation:(double)attenuation
durationFactor:(double)durationFactor
{
int mainSamples, totalSamples;
short int * data;
int i;
int zeroes;
double * leftString;
double * rightString;
double * leftPointer;
double * rightPointer;
int stringLength;
int offset;
double * rightEnd;
double * rightOffsetEnd;
double * leftEnd;
double * leftOffsetEnd;
int wrappedOffset;
double sample;
double filterValue;
// between mainSamples and totalSamples, we do a smooth release
mainSamples = (int) (duration * durationFactor * (double)SAMPLEFREQ);
totalSamples = mainSamples + MAXEXTRA;
// output sound buffer allocation
data = malloc (totalSamples * sizeof (short int));
// preparing two strings
stringLength = (SAMPLEFREQ / 2) / frequency;
offset = stringLength * position;
// we get a good triangle if offset ranges from 1 to stringLength - 1
if (offset < 1)
offset = 1;
if (offset > stringLength)
stringLength = offset + 1;
leftPointer = leftString = malloc (stringLength * sizeof (double));
rightPointer = rightString = malloc (stringLength * sizeof (double));
[self generateTriangle:leftString length:stringLength
volume:volume * 0.5 * 32767.0 // we split the amplitude into two waves
// also, we are going to short int range
maximumAt:offset];
bcopy (leftString, rightString, stringLength * sizeof (double));
// praparing bridge attenuation filter
filterValue = 0;
// prepare wrapping
rightEnd = rightString + stringLength - 1;
rightOffsetEnd = rightEnd - offset;
leftEnd = leftString + stringLength - 1;
leftOffsetEnd = leftEnd - offset;
wrappedOffset = offset - stringLength;
// preparing end detection
zeroes = 0;
for (i = 0; i < totalSamples; i++) { // break when we have enough zeroes
// CALCULATE NEW SAMPLE
// take right offset value
if (rightPointer > rightOffsetEnd)
sample = *(rightPointer + wrappedOffset);
else
sample = *(rightPointer + offset);
// add left offset value
if (leftPointer > leftOffsetEnd)
sample += *(leftPointer + wrappedOffset);
else
sample += *(leftPointer + offset);
// sample is ready - convert to 16 bit
data[i] = (short int) sample;
// decrement right
if (rightPointer == rightString )
rightPointer = rightEnd;
else
rightPointer --;
// increment left
if (++leftPointer > leftEnd)
leftPointer = leftString;
// right = - filtered left
filterValue = attenuation * (filterValue + *leftPointer);
*rightPointer = -filterValue;
// left = - (next right)
if (rightPointer == rightString)
*leftPointer = -(*rightEnd);
else
*leftPointer = -(*(rightPointer - 1));
// end detection
if (data[i] == 0) {
if (zeroes++ > NEEDED_ZEROES)
break;
}
else
zeroes = 0;
// switching to the release phase
if (i == mainSamples)
attenuation = 0.45; // moving fast towards zero
}
free (leftString);
free (rightString);
*buf = data;
return i;
}
@end
These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.