f@0: /* f@0: Cross-Modal DAW Prototype - Prototype of a simple Cross-Modal Digital Audio Workstation. f@0: f@0: Copyright (C) 2015 Queen Mary University of London (http://depic.eecs.qmul.ac.uk/) f@0: f@0: This program is free software: you can redistribute it and/or modify f@0: it under the terms of the GNU General Public License as published by f@0: the Free Software Foundation, either version 3 of the License, or f@0: (at your option) any later version. f@0: f@0: This program is distributed in the hope that it will be useful, f@0: but WITHOUT ANY WARRANTY; without even the implied warranty of f@0: MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the f@0: GNU General Public License for more details. f@0: f@0: You should have received a copy of the GNU General Public License f@0: along with this program. If not, see . f@0: */ f@0: package uk.ac.qmul.eecs.depic.daw.referencesound; f@0: f@0: import net.beadsproject.beads.core.AudioContext; f@0: import net.beadsproject.beads.core.Bead; f@0: import net.beadsproject.beads.core.UGen; f@0: import net.beadsproject.beads.data.Buffer; f@0: import net.beadsproject.beads.ugens.Envelope; f@0: import net.beadsproject.beads.ugens.Gain; f@0: import net.beadsproject.beads.ugens.WavePlayer; f@0: import uk.ac.qmul.eecs.depic.patterns.Range; f@0: import uk.ac.qmul.eecs.depic.patterns.Sequence; f@0: f@0: /** f@0: * Implements a sequence mapping using beads engine and simple wave tables ugens f@0: * f@0: * f@0: */ f@0: class BeadsWaveTableSequenceMapping extends BeadsSequenceMapping { f@0: private Range renderCurvePitchSpan; f@0: private Range renderValuePitchSpan; f@0: private static final float ATTACK_TIME_MS = 5.0f; f@0: f@0: static { f@0: /* loads the buffer for the PeakLevelPitchedUgen and stores it into staticBuffs */ f@0: int bufferLen = 4096; f@0: Buffer pulse = new Buffer(bufferLen); f@0: int pulseWidth = bufferLen/10; f@0: f@0: for(int i=0; i curvePitchSpan, Range valuePitchSpan){ f@0: super(ac); f@0: renderCurvePitchSpan = curvePitchSpan; f@0: renderValuePitchSpan = valuePitchSpan; f@0: } f@0: f@0: @Override f@0: protected PitchedUGen createRenderValueUGen(){ f@0: return new BufferPitchedUGen(ac, renderValuePitchSpan, Buffer.SINE); f@0: } f@0: f@0: @Override f@0: protected PitchedUGen createRenderCurveUGen(){ f@0: return new BufferPitchedUGen(ac, renderCurvePitchSpan, Buffer.SINE); f@0: } f@0: f@0: f@0: @Override f@0: protected Range getRenderValuePitchSpan() { f@0: return renderValuePitchSpan; f@0: } f@0: f@0: @Override f@0: protected Range getRenderCurvePitchSpan() { f@0: return renderCurvePitchSpan; f@0: } f@0: f@0: private class BufferPitchedUGen extends PitchedUGen { f@0: private Gain gain; f@0: private WavePlayer player; f@0: private float maxFreq; f@0: private float minFreq; f@0: private Envelope env; f@0: f@0: /** f@0: * f@0: * Pulse TriangularBuffer Square Saw Noise Sine f@0: * f@0: * @param ac f@0: * @param pitchSpan f@0: * @param buffer f@0: */ f@0: public BufferPitchedUGen(AudioContext ac, Range pitchSpan, Buffer buffer) { f@0: super(ac); f@0: if(maxFreq < minFreq){ f@0: throw new IllegalArgumentException("minFreq must be lower than maxFreq. minFreq: "+minFreq+" maxFreq:"+maxFreq ); f@0: } f@0: f@0: this.minFreq = pitchSpan.getStart(); f@0: this.maxFreq = pitchSpan.getEnd(); f@0: gain = new Gain(ac, 1, 0.5f); f@0: player = new WavePlayer(ac,minFreq,buffer); f@0: f@0: gain.addInput(player); f@0: f@0: addToChainOutput(gain); f@0: } f@0: f@0: @Override f@0: public void setPitch(float pitch){ f@0: /* set the frequency for both the actual curve sound and the threshold sound */ f@0: player.setFrequency(pitch); f@0: f@0: } f@0: f@0: @Override f@0: public void setPitch(UGen pitch) { f@0: player.setFrequency(pitch); f@0: } f@0: f@0: public float getFrequency(float freq){ f@0: return player.getFrequency(); f@0: } f@0: f@0: @Override f@0: public void start(){ f@0: player.start(); f@0: } f@0: f@0: f@0: @Override f@0: public void setLen(float sustainValue, float decayTime){ f@0: /* if decayTime is long enough, smooth out the attack to avoid glitchy sound */ f@0: if(Float.compare(decayTime,ATTACK_TIME_MS) > 0){ f@0: env = new Envelope(context,0.0f); // starts from 0 f@0: env.addSegment(sustainValue,ATTACK_TIME_MS,2); // attack f@0: env.addSegment(0.0f,decayTime-ATTACK_TIME_MS, this); // decay f@0: }else{ f@0: env = new Envelope(context,sustainValue); f@0: env.addSegment(0.0f, decayTime, this); // decay f@0: } f@0: gain.setGain(env); f@0: } f@0: f@0: @Override f@0: public void addLen(float sustainValue, float duration, final Bead bead){ f@0: if(env == null){ f@0: if(Float.compare(duration,ATTACK_TIME_MS) > 0){ f@0: env = new Envelope(context,0.0f); // starts from 0 f@0: env.addSegment(sustainValue,ATTACK_TIME_MS,2); // attack f@0: env.addSegment(sustainValue,duration-ATTACK_TIME_MS, bead); // decay f@0: }else{ f@0: env = new Envelope(context,sustainValue); f@0: env.addSegment(0.0f, duration, bead); // decay f@0: } f@0: gain.setGain(env); f@0: }else{ f@0: env.addSegment(sustainValue,duration, bead); f@0: } f@0: f@0: } f@0: f@0: @Override f@0: public void addLen(float sustainValue, float duration ){ f@0: if(env == null){ f@0: if(Float.compare(duration,ATTACK_TIME_MS) > 0){ f@0: env = new Envelope(context,0.0f); // starts from 0 f@0: env.addSegment(sustainValue,ATTACK_TIME_MS,2); // attack f@0: env.addSegment(sustainValue,duration-ATTACK_TIME_MS, this); // decay f@0: }else{ f@0: env = new Envelope(context,sustainValue); f@0: env.addSegment(sustainValue, duration, this); // decay f@0: } f@0: gain.setGain(env); f@0: }else{ f@0: env.addSegment(0.0f,duration, this); f@0: } f@0: f@0: } f@0: f@0: @Override f@0: public void messageReceived(Bead b){ f@0: kill(); f@0: } f@0: f@0: } f@0: f@0: @Override f@0: public void renderCurve(Sequence m, float startTime) { f@0: throw new UnsupportedOperationException(); f@0: } f@0: };;