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.