view src/uk/ac/qmul/eecs/depic/daw/referencesound/BeadsWaveTableSequenceMapping.java @ 0:3074a84ef81e

first import
author Fiore Martin <f.martin@qmul.ac.uk>
date Wed, 26 Aug 2015 16:16:53 +0100
parents
children
line wrap: on
line source
/*  
 Cross-Modal DAW Prototype - Prototype of a simple Cross-Modal Digital Audio Workstation.

 Copyright (C) 2015  Queen Mary University of London (http://depic.eecs.qmul.ac.uk/)
	
 This program is free software: you can redistribute it and/or modify
 it under the terms of the GNU General Public License as published by
 the Free Software Foundation, either version 3 of the License, or
 (at your option) any later version.

 This program is distributed in the hope that it will be useful,
 but WITHOUT ANY WARRANTY; without even the implied warranty of
 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 GNU General Public License for more details.

 You should have received a copy of the GNU General Public License
 along with this program.  If not, see <http://www.gnu.org/licenses/>.
*/
package uk.ac.qmul.eecs.depic.daw.referencesound;

import net.beadsproject.beads.core.AudioContext;
import net.beadsproject.beads.core.Bead;
import net.beadsproject.beads.core.UGen;
import net.beadsproject.beads.data.Buffer;
import net.beadsproject.beads.ugens.Envelope;
import net.beadsproject.beads.ugens.Gain;
import net.beadsproject.beads.ugens.WavePlayer;
import uk.ac.qmul.eecs.depic.patterns.Range;
import uk.ac.qmul.eecs.depic.patterns.Sequence;

/**
 * Implements a sequence mapping using beads engine and simple wave tables ugens 
 * 
 *
 */
class BeadsWaveTableSequenceMapping extends BeadsSequenceMapping { 
	private Range<Float> renderCurvePitchSpan;
	private Range<Float> renderValuePitchSpan;
	private static final float ATTACK_TIME_MS = 5.0f;
	
	static {
		/* loads the buffer for the PeakLevelPitchedUgen and stores it into staticBuffs */
		int bufferLen = 4096;
		Buffer pulse = new Buffer(bufferLen);
		int pulseWidth = bufferLen/10;
		
		for(int i=0; i<pulseWidth;i++){
			pulse.buf[i] = 1.0f;
		}
		
		for(int i=pulseWidth; i<bufferLen; i++){
			pulse.buf[i] = -1.0f;
		}
		
		Buffer.staticBufs.put("Pulse", pulse);
	}

	public BeadsWaveTableSequenceMapping(AudioContext ac, Range<Float> curvePitchSpan, Range<Float> valuePitchSpan){
		super(ac);
		renderCurvePitchSpan = curvePitchSpan;
		renderValuePitchSpan = valuePitchSpan;
	}
	
	@Override
	protected PitchedUGen createRenderValueUGen(){
		return new BufferPitchedUGen(ac, renderValuePitchSpan, Buffer.SINE);
	}
	
	@Override
	protected PitchedUGen createRenderCurveUGen(){
		return new BufferPitchedUGen(ac, renderCurvePitchSpan, Buffer.SINE);
	}
	

	@Override
	protected Range<Float> getRenderValuePitchSpan() {
		return renderValuePitchSpan;
	}

	@Override
	protected Range<Float> getRenderCurvePitchSpan() {
		return renderCurvePitchSpan;
	}
	
	private class BufferPitchedUGen extends PitchedUGen {
		private Gain gain;
		private WavePlayer player;
		private float maxFreq;
		private float minFreq;
		private Envelope env;
		
		/**
		 * 
		 * Pulse TriangularBuffer Square  Saw Noise Sine
		 * 
		 * @param ac
		 * @param pitchSpan
		 * @param buffer
		 */
		public BufferPitchedUGen(AudioContext ac, Range<Float> pitchSpan, Buffer buffer) {
			super(ac);
			if(maxFreq < minFreq){
				throw new IllegalArgumentException("minFreq must be lower than maxFreq. minFreq: "+minFreq+" maxFreq:"+maxFreq );
			}
			
			this.minFreq = pitchSpan.getStart();
			this.maxFreq = pitchSpan.getEnd();
			gain = new Gain(ac, 1, 0.5f);
			player = new WavePlayer(ac,minFreq,buffer);
			
			gain.addInput(player);
			
			addToChainOutput(gain);
		}
		
		@Override
		public void setPitch(float pitch){
			/* set the frequency for both the actual curve sound and the threshold sound */
			player.setFrequency(pitch);
			
		}
		
		@Override
		public void setPitch(UGen pitch) {
			player.setFrequency(pitch);
		}
		
		public float getFrequency(float freq){
			return player.getFrequency();
		}
		
		@Override
		public void start(){
			player.start();
		}
		
			
		@Override
		public void setLen(float sustainValue, float decayTime){
			/* if decayTime is long enough, smooth out the attack to avoid glitchy sound */
			if(Float.compare(decayTime,ATTACK_TIME_MS) > 0){
				env = new Envelope(context,0.0f); // starts from 0
				env.addSegment(sustainValue,ATTACK_TIME_MS,2); // attack
				env.addSegment(0.0f,decayTime-ATTACK_TIME_MS, this);  // decay
			}else{
				env = new Envelope(context,sustainValue);
				env.addSegment(0.0f, decayTime, this); // decay
			}
			gain.setGain(env);
		}
		
		@Override
		public void addLen(float sustainValue, float duration, final Bead bead){
			if(env == null){
				if(Float.compare(duration,ATTACK_TIME_MS) > 0){
					env = new Envelope(context,0.0f); // starts from 0
					env.addSegment(sustainValue,ATTACK_TIME_MS,2); // attack
					env.addSegment(sustainValue,duration-ATTACK_TIME_MS, bead);  // decay
				}else{
					env = new Envelope(context,sustainValue);
					env.addSegment(0.0f, duration, bead); // decay
				}			
				gain.setGain(env);
			}else{	
				env.addSegment(sustainValue,duration, bead);
			}
			
		}
		
		@Override
		public void addLen(float sustainValue, float duration ){
			if(env == null){
				if(Float.compare(duration,ATTACK_TIME_MS) > 0){
					env = new Envelope(context,0.0f); // starts from 0
					env.addSegment(sustainValue,ATTACK_TIME_MS,2); // attack
					env.addSegment(sustainValue,duration-ATTACK_TIME_MS, this);  // decay
				}else{
					env = new Envelope(context,sustainValue);
					env.addSegment(sustainValue, duration, this); // decay
				}			
				gain.setGain(env);
			}else{
				env.addSegment(0.0f,duration, this);
			}
			
		}
		
		@Override
		public void messageReceived(Bead b){
			kill();
		}
		
	}

	@Override
	public void renderCurve(Sequence m, float startTime) {
		throw new UnsupportedOperationException();
	}
};;