davem@cm-next-2.Stanford.EDU (08/04/90)
In a music kit Partials object, the only 'scaling' value that works in computing a wavetable for the Partials object is 0.0, for normalization scaling. ("Normalization scaling" means that the values in the wavetable are all scaled up or down by the same amount so that the maximum value in the table is the maximum value that a DSP 24-bit integer can hold, 2^23 - 1.) Other values for the Partials's scaling parameter produce an incomplete or erroneous wavetable when you ask for the wavetable with the 'dataDSP' message or its kin. Also, when you hand a Partials object to an oscillator unitgenerator for specifying a wavetable, there is no way to specify a scaling value to use. So you're always stuck with normalization scaling anyway. The method below, which I use in a SynthPatch subclass, fixes these problems. It works by generating the wavetable using the usual normalization scaling. Then it computes a scaling value, which is the return value, that can be used as an 'amp' parameter (or multiplied by another 'amp' parameter) to give true absolute scaling. You need to call this method whenever your wavetable changes, which is usually whenever your Partials object changes. You could also use the return value from this method to multiply each wavetable entry by, rather that using it as an 'amp' parameter, but then you must be extremely careful that the wavetable in the Partials object never gets recomputed. You also lose some resolution in the wavetable this way. Dave Mellinger davem@cs.Stanford.EDU /* This method necessary because the only non-buggy scaling available in * a Partials object is normalization scaling. Since we want absolute * scaling, we have to first compute the samples * (with [partials dataDSP]), then compute a value to use for * scaling to the originally intended size. This value, which is * the return value, can be used in an 'amp' parameter. */ #import <musickit/musickit.h> #import <musickit/Partials.h> - (double)ampForDataDSP:(id)partials { DSPDatum *buf; int len, np, i; double xx, sum, phase; double *amps, *freqs, *phases; /* make dataDSP with normalization scaling */ buf = [partials dataDSP]; len = [partials length]; np = [partials partialCount]; amps = [partials ampRatios]; freqs = [partials freqRatios]; phases = [partials phases]; phase = [partials defaultPhase]; /* find where the maximum wavetable value occurs */ for (i = 0; i < len; i++) if (buf[i] == DSP_I_MAXPOS || buf[i] == -DSP_I_MAXPOS) break; if (i == len) { fprintf(stderr, "ampForDataDSP: Can't find max wavetable value.\n"); return 1.0; } xx = (float)i / len * 2 * M_PI; /* compute correct (absolute scaling) value at that wavetable position */ sum = 0.0; for (i = 0; i < np; i++) sum += amps[i] * sin(xx * freqs[i] + (phases ? phases[i] : phase)); /* amplitudes > 1.0 usually cause overflow in the DSP */ if (sum > 1.0 || sum < -1.0) { fprintf(stderr, "ampForDataDSP: sum is too large!\n"); return 1.0; } return sum >= 0 ? sum : -sum; }