// ====================================================================== // W space: Multi star - fractal sound creation tool // (CC) 2009 Jens Koeplinger, http://www.jenskoeplinger.com/P // License: Creative Commons Attribution "Share Alike 3.0 Unported" // http://creativecommons.org/licenses/by-sa/3.0 // See main file "wspacemultistarsound.c" for what this means to you! // ====================================================================== // lib-multistar-sweep.h // ---------------------------------------------------------------------- // library that calculates the requested wave table sweeps // // Examples: /* totalDataLength = calculateTotalDataLength(); calculateSweep(); */ // ---------------------------------------------------------------------- int calculateTotalDataLength() { // calculates the complete wave sample length, based // on the requested sweeps // // IN: totalLength (seconds) for multi-star fractal sound computation; // testLength (when in sine, saw, or square test mode) switch (outputMode) { case 0: // fractal mode (regular) return ((int) (totalLength * 44100.)) * 4; case 1: // test: sine case 2: // test: saw case 3: // test: square // return requested length (in seconds; double), // multiplied by the sampling rate (44.1kHz), rounded // to whole samples, and then multiplied with 4 // (16 bits per channel = 4 bytes per sample) return ((int) (testLength * 44100.)) * 4; default: // huh? printf("calculateTotalDataLength():outputMode=%d\n", outputMode); printf("Unknown / unexpected; aborting.\n"); return 0; } } // ---------------------------------------------------------------------- void calculateSweep() { // based on command line parameters, calculates the // selected sweep over the multi-star fractal (or a // test tone, if selected), and writes the result into // the (open) output WAV file. switch (outputMode) { case 0: // multi-star (regular) fractal computation calculateFractalSweep(); break; case 1: // test: sine case 2: // test: saw case 3: // test: square calculateTestSweep(); break; default: // huh? printf("calculateSweep():outputMode=%d\n", outputMode); printf("Unknown / unexpected; aborting.\n"); return; } } // ---------------------------------------------------------------------- void calculateTestSweep() { // for outputMode 1,2,3: calculate the sine,saw,square test samples int i; // throwaway: sample counter double d; // throwaway double double sampleI; // ... sample counter as double double samplePleft; // position in sample period, left channel double samplePright; // ... right channel double periodLengthLeft; // length (double) of one period on left channel double periodLengthRight; // ... right channel double vLeft; // sample amplitude left double vRight; // ... right i = (int) (testLength * 44100.); // total number of samples periodLengthLeft = 44100. / testFLeft; periodLengthRight = 44100. / testFRight; while (i > 0) { // loop through the samples, and create test wave form i--; sampleI = (double) i; // subtract multiples of the period length d = (double) ( (int) (sampleI / periodLengthLeft)); samplePleft = sampleI - (d * periodLengthLeft); d = (double) ( (int) (sampleI / periodLengthRight)); samplePright = sampleI - (d * periodLengthRight); // generate wave form switch (outputMode) { case 1: // test: sine vLeft = testAmplitude * sin((2. * PI * samplePleft ) / periodLengthLeft ); vRight = testAmplitude * sin((2. * PI * samplePright) / periodLengthRight); break; case 2: // test: saw if ((samplePleft / periodLengthLeft) < 0.5) { vLeft = 4. * testAmplitude * ((samplePleft / periodLengthLeft) - 0.25); } else { vLeft = 4. * testAmplitude * (0.75 - (samplePleft / periodLengthLeft)); } if ((samplePright / periodLengthRight) < 0.5) { vRight = 4. * testAmplitude * ((samplePright / periodLengthRight) - 0.25); } else { vRight = 4. * testAmplitude * (0.75 - (samplePright / periodLengthRight)); } break; case 3: // test: square if ((samplePleft / periodLengthLeft) < 0.5) vLeft = testAmplitude; else vLeft = 0. - testAmplitude; if ((samplePright / periodLengthRight) < 0.5) vRight = testAmplitude; else vRight = 0. - testAmplitude; break; default: // error printf("calculateTestSweep:outputMode=%d\n", outputMode); printf("error/unexpected; aborting.\n"); return; } writeTwoByteInteger(fp, ((int) vLeft)); writeTwoByteInteger(fp, ((int) vRight)); // one sample written } // all data written: // sample creation done. } // ---------------------------------------------------------------------- void calculateFractalSweep() { // calculate the multi-star fractal sound, either static or a sweep; int thisCounter; // integer counter, from 0 to totalCount - 1 int totalCount; // (int) (totalLength * 44100.) double d; // throwaway double totalCountDouble; // -"- double thisCounterPercent; // percent complete, from 0. to < 1. double thisAmplitude; // amplitude percentage (if variable) double periodLength; // number of samples per period (in double) double thisAngle; // current angle double thisConvergencePercent; // current convergence percentage double thisRadius; // radius of the current convergence percentage (at thisAngle) thisCounter = 0; totalCount = (int) (totalLength * 44100.); totalCountDouble = (double) totalCount; periodLength = 44100. / baseFrequency; printf("Calculating multi-star; total length: %f seconds (%d samples).\n", totalLength, totalCount); while (thisCounter < totalCount) { // calculate the fractal, one bin at a time thisCounterPercent = ((double) thisCounter) / totalCountDouble; thisAmplitude = (amplitudeMultiplier * (1. - thisCounterPercent)) + (amplitudeSweepTo * thisCounterPercent); // calculate angle in the multi-star; limit to the [0, 2pi[ interval thisAngle = ((double) thisCounter) / periodLength; // "angle" is 0. to 1. (not yet multiplied with 2pi) and multiples d = (double) ( (int) (thisAngle) ); // number of complete periods already played thisAngle = (thisAngle - d) * 2. * PI; // subtrac full periods, and make a real angle in the [0, 2pi[ interval if (isSweep == 0) { // plays a static convergence percentage thisConvergencePercent = convergencePercentage; } else if (isContinuous == 0) { // plays a set of distinct percentages (stepped) // *** TEMPORARY: ABORT - not implemented yet printf("TEMPORARY: ABORT - non-continuous (stepped) sweeps not implemented yet.\n"); return; } else { // plays a continuous sweep from one convergence // percentage to another thisConvergencePercent = (convergencePercentage * (1. - thisCounterPercent)) + (convergenceSweepTo * thisCounterPercent); } // all parameters prior to doing the actual fractal calculation are now set; // ==> do it: calculate radius in the unit multi-star, and then bring it // to a 0..32766 radius for 100% output (thisAmplitude = 1.) thisRadius = calculateRadius(thisConvergencePercent, thisAngle, thisAmplitude); thisRadius = thisRadius * 32766. * thisAmplitude; // write the projection of the real axis to the right channel, and the // projection of the w axis to the left channel writeTwoByteInteger(fp, ((int) (sin(thisAngle) * thisRadius) )); // left channel: W part writeTwoByteInteger(fp, ((int) (cos(thisAngle) * thisRadius) )); // right channel: real part // sample written; next one: thisCounter++; if ((thisCounter % 4410) == 0) { // every 1/10s of samples rendered, give a status update printf("...completed: %f seconds (%d samples).\n", ((double) thisCounter) / 44100., thisCounter); } } // all done; time to listen to the sound of a fractal }