import java.math.*; class SongIterator implements AudioSignal { long time; BigInteger current; int sampleRate, sampleLength, samplePosition, noteLength, notePosition, fadeLength; float[] notes; float[] fade; SongIterator(int sampleRate, float[] notes, int fadeLength) { this.sampleRate = sampleRate; this.fadeLength = fadeLength; reset(notes); } void reset(float[] notes) { this.notes = notes; sampleLength = (int) Math.ceil(sampleRate / notes[0]); time = 0; samplePosition = 0; notePosition = 0; current = new BigInteger("1"); fade = new float[fadeLength]; float normalize = TWO_PI / sampleRate; for(int i = 0; i < notes.length; i++) this.notes[i] *= normalize; } void random(int bits) { current = new BigInteger(bits, new Random()); } void generate(float[] samp) { boolean resync = false; for(int i = 0; i < samp.length; i++) { int total = current.bitLength(); noteLength = (int) Math.ceil((float) total / notes.length); if(samplePosition < fadeLength) { float fadeValue = (float) samplePosition / fadeLength; samp[i] = (getSample(time) * fadeValue) + ((1 - fadeValue) * fade[samplePosition]); } else { samp[i] = getSample(time); } time++; samplePosition++; if(samplePosition % sampleLength == 0) { for(int j = 0; j < fadeLength; j++) fade[j] = getSample(time + j); samplePosition = 0; notePosition++; if(notePosition % noteLength == 0) { notePosition = 0; current = current.add(BigInteger.ONE); } } } } float getSample(long time) { float sample = 0; float on = 0; for(int i = notes.length * notePosition; i < notes.length * (notePosition + 1); i++) { int ai = i % notes.length; if(current.testBit(i)) { sample += sin(notes[ai] * time); on++; } } return sample / on; } void generate(float[] left, float[] right) { generate(left); generate(right); } }