Marek Bereza avatar Marek Bereza committed f70529d

Started player sub-framework

Comments (0)

Files changed (20)

Binary file added.

+{\rtf1\ansi\ansicpg1252\cocoartf1138\cocoasubrtf100
+{\fonttbl\f0\fswiss\fcharset0 Helvetica;}
+{\colortbl;\red255\green255\blue255;}
+\paperw11900\paperh16840\margl1440\margr1440\vieww10800\viewh8400\viewkind0
+\pard\tx566\tx1133\tx1700\tx2267\tx2834\tx3401\tx3968\tx4535\tx5102\tx5669\tx6236\tx6803\pardirnatural
+
+\f0\fs24 \cf0 create players \
+	LoopFader\
+		- control range - modulation frequency\
+RandomSoundEmitter\
+	- control the random volume range\
+	- allow fade ins\
+\pard\tx566\tx1133\tx1700\tx2267\tx2834\tx3401\tx3968\tx4535\tx5102\tx5669\tx6236\tx6803\pardirnatural
+\cf0 xml files\
+personality class\
+\
+\
+\
+// maybes\
+optimize locking\
+\pard\tx566\tx1133\tx1700\tx2267\tx2834\tx3401\tx3968\tx4535\tx5102\tx5669\tx6236\tx6803\pardirnatural
+\cf0 speed up, slow down\
+cross fade loop\
+filters - maybe a global filter?\
+\
+envelopes\
+\
+\pard\tx566\tx1133\tx1700\tx2267\tx2834\tx3401\tx3968\tx4535\tx5102\tx5669\tx6236\tx6803\pardirnatural
+\cf0 exponential fades}

audioOutputExample.xcodeproj/project.pbxproj

 		E4C2424810CC5A17004149E2 /* Cocoa.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = E4C2424510CC5A17004149E2 /* Cocoa.framework */; };
 		E4C2424910CC5A17004149E2 /* IOKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = E4C2424610CC5A17004149E2 /* IOKit.framework */; };
 		E4EB6799138ADC1D00A09F29 /* GLUT.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = BBAB23BE13894E4700AA2426 /* GLUT.framework */; };
-		EA11C3C013E7FD3E00D41E78 /* AudioSystem.cpp in Sources */ = {isa = PBXBuildFile; fileRef = EA11C3BA13E7FD3E00D41E78 /* AudioSystem.cpp */; };
-		EA11C3C113E7FD3E00D41E78 /* StereoSample.cpp in Sources */ = {isa = PBXBuildFile; fileRef = EA11C3BD13E7FD3E00D41E78 /* StereoSample.cpp */; };
+		EA11C3F713E8346600D41E78 /* AudioSystem.cpp in Sources */ = {isa = PBXBuildFile; fileRef = EA11C3EC13E8346600D41E78 /* AudioSystem.cpp */; };
+		EA11C3F813E8346600D41E78 /* StereoSample.cpp in Sources */ = {isa = PBXBuildFile; fileRef = EA11C3EF13E8346600D41E78 /* StereoSample.cpp */; };
+		EA11C3F913E8346600D41E78 /* Personality.cpp in Sources */ = {isa = PBXBuildFile; fileRef = EA11C3F313E8346600D41E78 /* Personality.cpp */; };
+		EA11C40613E838D800D41E78 /* tinyxml.cpp in Sources */ = {isa = PBXBuildFile; fileRef = EA11C3FF13E838D800D41E78 /* tinyxml.cpp */; };
+		EA11C40713E838D800D41E78 /* tinyxmlerror.cpp in Sources */ = {isa = PBXBuildFile; fileRef = EA11C40113E838D800D41E78 /* tinyxmlerror.cpp */; };
+		EA11C40813E838D800D41E78 /* tinyxmlparser.cpp in Sources */ = {isa = PBXBuildFile; fileRef = EA11C40213E838D800D41E78 /* tinyxmlparser.cpp */; };
+		EA11C40913E838D800D41E78 /* ofxXmlSettings.cpp in Sources */ = {isa = PBXBuildFile; fileRef = EA11C40413E838D800D41E78 /* ofxXmlSettings.cpp */; };
 /* End PBXBuildFile section */
 
 /* Begin PBXContainerItemProxy section */
 		E4C2424610CC5A17004149E2 /* IOKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = IOKit.framework; path = /System/Library/Frameworks/IOKit.framework; sourceTree = "<absolute>"; };
 		E4EB691F138AFCF100A09F29 /* CoreOF.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = CoreOF.xcconfig; path = ../../../libs/openFrameworksCompiled/project/osx/CoreOF.xcconfig; sourceTree = SOURCE_ROOT; };
 		E4EB6923138AFD0F00A09F29 /* Project.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; path = Project.xcconfig; sourceTree = "<group>"; };
-		EA11C3BA13E7FD3E00D41E78 /* AudioSystem.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = AudioSystem.cpp; sourceTree = "<group>"; };
-		EA11C3BB13E7FD3E00D41E78 /* AudioSystem.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AudioSystem.h; sourceTree = "<group>"; };
-		EA11C3BC13E7FD3E00D41E78 /* Sample.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Sample.h; sourceTree = "<group>"; };
-		EA11C3BD13E7FD3E00D41E78 /* StereoSample.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = StereoSample.cpp; sourceTree = "<group>"; };
-		EA11C3BE13E7FD3E00D41E78 /* StereoSample.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = StereoSample.h; sourceTree = "<group>"; };
-		EA11C3BF13E7FD3E00D41E78 /* WavFile.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = WavFile.h; sourceTree = "<group>"; };
 		EA11C3C213E7FDF500D41E78 /* LoopFadeInOut.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = LoopFadeInOut.h; sourceTree = "<group>"; };
 		EA11C3C313E7FDF500D41E78 /* RandomSoundEmitter.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RandomSoundEmitter.h; sourceTree = "<group>"; };
 		EA11C3C413E7FDF500D41E78 /* VolumeController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = VolumeController.h; sourceTree = "<group>"; };
+		EA11C3EC13E8346600D41E78 /* AudioSystem.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = AudioSystem.cpp; sourceTree = "<group>"; };
+		EA11C3ED13E8346600D41E78 /* AudioSystem.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AudioSystem.h; sourceTree = "<group>"; };
+		EA11C3EE13E8346600D41E78 /* Sample.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Sample.h; sourceTree = "<group>"; };
+		EA11C3EF13E8346600D41E78 /* StereoSample.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = StereoSample.cpp; sourceTree = "<group>"; };
+		EA11C3F013E8346600D41E78 /* StereoSample.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = StereoSample.h; sourceTree = "<group>"; };
+		EA11C3F113E8346600D41E78 /* WavFile.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = WavFile.h; sourceTree = "<group>"; };
+		EA11C3F313E8346600D41E78 /* Personality.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = Personality.cpp; sourceTree = "<group>"; };
+		EA11C3F413E8346600D41E78 /* Personality.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Personality.h; sourceTree = "<group>"; };
+		EA11C3F613E8346600D41E78 /* Player.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Player.h; sourceTree = "<group>"; };
+		EA11C3FB13E8371C00D41E78 /* personality1.xml */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xml; name = personality1.xml; path = bin/data/personality1.xml; sourceTree = "<group>"; };
+		EA11C3FD13E838D800D41E78 /* install.xml */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xml; path = install.xml; sourceTree = "<group>"; };
+		EA11C3FF13E838D800D41E78 /* tinyxml.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = tinyxml.cpp; sourceTree = "<group>"; };
+		EA11C40013E838D800D41E78 /* tinyxml.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = tinyxml.h; sourceTree = "<group>"; };
+		EA11C40113E838D800D41E78 /* tinyxmlerror.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = tinyxmlerror.cpp; sourceTree = "<group>"; };
+		EA11C40213E838D800D41E78 /* tinyxmlparser.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = tinyxmlparser.cpp; sourceTree = "<group>"; };
+		EA11C40413E838D800D41E78 /* ofxXmlSettings.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ofxXmlSettings.cpp; sourceTree = "<group>"; };
+		EA11C40513E838D800D41E78 /* ofxXmlSettings.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ofxXmlSettings.h; sourceTree = "<group>"; };
+		EA11C40A13E838DE00D41E78 /* OneShot.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OneShot.h; sourceTree = "<group>"; };
 /* End PBXFileReference section */
 
 /* Begin PBXFrameworksBuildPhase section */
 		BB4B014C10F69532006C3DED /* addons */ = {
 			isa = PBXGroup;
 			children = (
+				EA11C3FC13E838D800D41E78 /* ofxXmlSettings */,
 			);
 			name = addons;
 			sourceTree = "<group>";
 		E4B69B4A0A3A1720003C02F2 = {
 			isa = PBXGroup;
 			children = (
+				EA11C3FB13E8371C00D41E78 /* personality1.xml */,
 				E4B6FCAD0C3E899E008CF71C /* openFrameworks-Info.plist */,
 				E4EB6923138AFD0F00A09F29 /* Project.xcconfig */,
 				E4B69E1C0A3A1BDC003C02F2 /* src */,
 		EA11C3B913E7FD3E00D41E78 /* AudioEngine */ = {
 			isa = PBXGroup;
 			children = (
-				EA11C3BA13E7FD3E00D41E78 /* AudioSystem.cpp */,
-				EA11C3BB13E7FD3E00D41E78 /* AudioSystem.h */,
-				EA11C3BC13E7FD3E00D41E78 /* Sample.h */,
-				EA11C3BD13E7FD3E00D41E78 /* StereoSample.cpp */,
-				EA11C3BE13E7FD3E00D41E78 /* StereoSample.h */,
-				EA11C3BF13E7FD3E00D41E78 /* WavFile.h */,
+				EA11C3EB13E8346600D41E78 /* core */,
+				EA11C3F213E8346600D41E78 /* player */,
 			);
 			path = AudioEngine;
 			sourceTree = "<group>";
 		};
+		EA11C3EB13E8346600D41E78 /* core */ = {
+			isa = PBXGroup;
+			children = (
+				EA11C3EC13E8346600D41E78 /* AudioSystem.cpp */,
+				EA11C3ED13E8346600D41E78 /* AudioSystem.h */,
+				EA11C3EE13E8346600D41E78 /* Sample.h */,
+				EA11C3EF13E8346600D41E78 /* StereoSample.cpp */,
+				EA11C3F013E8346600D41E78 /* StereoSample.h */,
+				EA11C3F113E8346600D41E78 /* WavFile.h */,
+			);
+			path = core;
+			sourceTree = "<group>";
+		};
+		EA11C3F213E8346600D41E78 /* player */ = {
+			isa = PBXGroup;
+			children = (
+				EA11C3F313E8346600D41E78 /* Personality.cpp */,
+				EA11C3F413E8346600D41E78 /* Personality.h */,
+				EA11C3F613E8346600D41E78 /* Player.h */,
+				EA11C40A13E838DE00D41E78 /* OneShot.h */,
+			);
+			path = player;
+			sourceTree = "<group>";
+		};
+		EA11C3FC13E838D800D41E78 /* ofxXmlSettings */ = {
+			isa = PBXGroup;
+			children = (
+				EA11C3FD13E838D800D41E78 /* install.xml */,
+				EA11C3FE13E838D800D41E78 /* libs */,
+				EA11C40313E838D800D41E78 /* src */,
+			);
+			name = ofxXmlSettings;
+			path = ../../../addons/ofxXmlSettings;
+			sourceTree = "<group>";
+		};
+		EA11C3FE13E838D800D41E78 /* libs */ = {
+			isa = PBXGroup;
+			children = (
+				EA11C3FF13E838D800D41E78 /* tinyxml.cpp */,
+				EA11C40013E838D800D41E78 /* tinyxml.h */,
+				EA11C40113E838D800D41E78 /* tinyxmlerror.cpp */,
+				EA11C40213E838D800D41E78 /* tinyxmlparser.cpp */,
+			);
+			path = libs;
+			sourceTree = "<group>";
+		};
+		EA11C40313E838D800D41E78 /* src */ = {
+			isa = PBXGroup;
+			children = (
+				EA11C40413E838D800D41E78 /* ofxXmlSettings.cpp */,
+				EA11C40513E838D800D41E78 /* ofxXmlSettings.h */,
+			);
+			path = src;
+			sourceTree = "<group>";
+		};
 /* End PBXGroup section */
 
 /* Begin PBXNativeTarget section */
 			files = (
 				E4B69E200A3A1BDC003C02F2 /* main.cpp in Sources */,
 				E4B69E210A3A1BDC003C02F2 /* testApp.cpp in Sources */,
-				EA11C3C013E7FD3E00D41E78 /* AudioSystem.cpp in Sources */,
-				EA11C3C113E7FD3E00D41E78 /* StereoSample.cpp in Sources */,
+				EA11C3F713E8346600D41E78 /* AudioSystem.cpp in Sources */,
+				EA11C3F813E8346600D41E78 /* StereoSample.cpp in Sources */,
+				EA11C3F913E8346600D41E78 /* Personality.cpp in Sources */,
+				EA11C40613E838D800D41E78 /* tinyxml.cpp in Sources */,
+				EA11C40713E838D800D41E78 /* tinyxmlerror.cpp in Sources */,
+				EA11C40813E838D800D41E78 /* tinyxmlparser.cpp in Sources */,
+				EA11C40913E838D800D41E78 /* ofxXmlSettings.cpp in Sources */,
 			);
 			runOnlyForDeploymentPostprocessing = 0;
 		};

bin/data/personality1.xml

+<oneshot output1="0" output2="1">
+    <sound file="drop1.wav" />
+    <sound file="drop2.wav" />
+    <sound file="drop3.wav" />
+    <sound file="drop4.wav" />
+</oneshot>

src/AudioEngine/AudioSystem.cpp

-/*
- *  AudioSystem.cpp
- *  AudioTest
- *
- *  Created by Marek Bereza on 01/09/2010.
- *  Copyright 2010 Marek Bereza. All rights reserved.
- *
- */
-
-
-#include "AudioSystem.h"
-#ifdef WIN32
-#include <Windows.h>
-#include <process.h>
-CRITICAL_SECTION  critSec;  	//same as a mutex
-#else
-#include <pthread.h>
-#include <semaphore.h>
-pthread_mutex_t  myMutex;
-#endif
-
-
-
-
-
-using namespace audio;
-
-AudioSystem audioSystem;
-
-AudioSystem *audio::getAudioSystem() {
-	return &audioSystem;
-}
-
-#ifdef USING_RTAUDIO
-
-// audio callback
-int audioCallback( void *outputBuffer, void *inputBuffer, unsigned int nBufferFrames,
-         double streamTime, RtAudioStreamStatus status, void *userData ) {
-			   
-  float *buffer = (float *) outputBuffer;
-  AudioSystem *as = (AudioSystem *) userData;
-
-  as->getSamples(buffer, nBufferFrames, 2);
-
-  return 0;
-}
-#endif
-
-AudioSystem::AudioSystem() {
-	sampleRefCounter = 0;
-	playerRefCounter = 0;
-	masterVolume = 1.0;
-    softSaturation = false;
-    saturationSoftness = 0.5;
-#ifdef USING_RTAUDIO
-	rtAudio = NULL;
-#endif
-	enabled = true;
-#ifdef WIN32 
-	InitializeCriticalSection(&critSec); 
-#else 
-	pthread_mutex_init(&myMutex, NULL); 
-#endif 
-	
-}
-
-
-AudioSystem::~AudioSystem() {
-
-#ifndef WIN32 
-	pthread_mutex_destroy(&myMutex); 
-#endif 
-}
-
-void audio::setMasterVolume(float volume, bool softSaturation, float saturationSoftness) {
-	if(volume>1.0) volume = 1.0;
-	if(volume<0) volume = 0;
-	audioSystem.lock();
-	audioSystem.masterVolume = volume;
-    audioSystem.softSaturation = softSaturation;
-    audioSystem.saturationSoftness = saturationSoftness;
-	audioSystem.unlock();
-}
-
-#ifdef USING_RTAUDIO
-bool audio::begin(int deviceId) {
-
-	audioSystem.lock();
-	if(!audioSystem.enabled) return false;
-	audioSystem.unlock();
-		
-	if(audioSystem.rtAudio!=NULL) delete audioSystem.rtAudio;
-
-	audioSystem.rtAudio = new RtAudio();
-
-
-	unsigned int devices = audioSystem.rtAudio->getDeviceCount();
-	cout << "found " << devices << " audio devices"<<endl;
-	
-	if(deviceId==-1) deviceId = audioSystem.rtAudio->getDefaultOutputDevice();
-	
-	string currDeviceName = "";
-	// Scan through devices for various capabilities
-	RtAudio::DeviceInfo info;
-	for ( unsigned int i=0; i<devices; i++ ) {
-		
-		info = audioSystem.rtAudio->getDeviceInfo( i );
-		if(deviceId==i) {
-			currDeviceName = info.name;
-		}
-		if ( info.probed == true ) {
-			// Print, for example, the maximum number of output channels for each device
-			std::cout << "device = " << i << "  - " << info.name;
-			std::cout << ": maximum output channels = " << info.outputChannels << "\n";
-
-			
-			
-    }
-  }
-
-
-	
-	cout << "Using device (" << deviceId << ") - " << currDeviceName << endl; 
-	RtAudio::StreamParameters parameters;
-	parameters.deviceId = deviceId;
-	parameters.nChannels = 2;
-	parameters.firstChannel = 0;
-	unsigned int sampleRate = 44100;
-	unsigned int bufferFrames = 1024; // 256 sample frames
-		
-
-	try {
-		audioSystem.rtAudio->openStream( &parameters, NULL, RTAUDIO_FLOAT32,
-                   sampleRate, &bufferFrames, &audioCallback, (void *)&audioSystem );
-		audioSystem.rtAudio->startStream();
-		return true;
-	} catch ( RtError& e ) {
-	    cout << "Couldn't connect to device " << endl;
-	   	e.printMessage();
-	    return false;
-	}
-}
-
-bool audio::end() {
-	audioSystem.lock();
-	if(!audioSystem.enabled) return false;
-	audioSystem.unlock();
-	try {
-
-		if ( audioSystem.rtAudio->isStreamOpen() ) {
-
-			
-			audioSystem.rtAudio->closeStream();
-			//audioSystem.rtAudio->abortStream();
-			
-			cout << "Closed audio successfully" << endl;
-			// kills the stream immediately - we need to do this because the destructor comes immediately after.
-			
-			reset();
-		}
-		return true;
-	} catch(RtError& e) {
-		cout << "Couldn't close device" << endl;
-		e.printMessage();
-	}
-	return false;
-}
-
-
-#endif
-void AudioSystem::lock() {
-#ifdef WIN32 
-	EnterCriticalSection(&critSec); 
-#else 
-	pthread_mutex_lock(&myMutex); 
-#endif 
-}
-
-void AudioSystem::unlock() {
-#ifdef WIN32 
-	LeaveCriticalSection(&critSec); 
-#else 
-	pthread_mutex_unlock(&myMutex); 
-#endif 
-}
-
-void audio::reset() {
-	audioSystem.commandList.clear();
-
-	map<SampleRef, WavFile*>::iterator a;
-	for(a = audioSystem.audioSamples.begin(); a != audioSystem.audioSamples.end(); a++) {
-		delete (*a).second;
-	}
-	audioSystem.audioSamples.clear();
-
-	map<PlayerRef, StereoSample*>::iterator b;
-	for(b = audioSystem.players.begin(); b != audioSystem.players.end(); b++) {
-		delete (*b).second;
-	}
-	audioSystem.players.clear();
-}
-
-void audio::play(PlayerRef playerId, float timeDelay) {
-	
-	audioSystem.addCommand(playerId, PLAY, timeDelay);
-
-}
-
-
-/**
- * Stops a sample from playing
- */
-void audio::stop(PlayerRef playerId) {
-	audioSystem.addCommand(playerId, STOP);
-}
-
-
-/**
- * Sets whether a sample is looping or not.
- */
-void audio::setLooping(PlayerRef playerId, bool looping) {
-	audioSystem.addCommand(playerId, LOOP, looping ? 1.0f : 0.0f);
-}
-
-void audio::setMix(PlayerRef playerId, float volume, float pan) {
-	audioSystem.lock();
-	audioSystem.commandList.push_back(AudioCommand(playerId, VOLUME, volume));
-	audioSystem.commandList.push_back(AudioCommand(playerId, PAN, pan));
-	audioSystem.unlock();
-}
-
-
-void audio::setPan(PlayerRef playerId, float pan) {
-	audioSystem.addCommand(playerId, PAN, pan);
-}
-
-void audio::setVolume(PlayerRef playerId, float volume) {
-	audioSystem.addCommand(playerId, VOLUME, volume);
-}
-
-void audio::setOutput(PlayerRef playerId, int channel1, int channel2) {
-    audioSystem.addCommand(playerId, OUTPUT, channel1, channel2);
-}
-
-
-void AudioSystem::addCommand(PlayerRef playerId, CommandType type, float parameter1, float parameter2) {
-	//lock();
-	commandList.push_back(AudioCommand(playerId, type, parameter1, parameter2));
-	//unlock();
-}
-
-int secondsToSamples(float seconds) {
-	float samples = 44100.f*seconds;
-	return (int) samples;
-}
-
-void AudioSystem::getSamples(float *samples, int length, int numChannels) {
-
-	memset(samples, 0, numChannels*sizeof(float)*length);
-	
-	lock();
-	if(!enabled) return;
-	for(unsigned int i = 0; i < commandList.size(); i++) {
-		if(commandList[i].playerId==0) {
-			cout << "Trying to play unallocated sample!!" << endl;
-			continue;
-		}
-		
-		
-		switch(commandList[i].type) {
-				
-			case PLAY:
-				players[commandList[i].playerId]->trigger(-secondsToSamples(commandList[i].parameter1));
-				break;
-            case OUTPUT:
-                players[commandList[i].playerId]->setOutputs(commandList[i].parameter1, commandList[i].parameter2);
-                break;
-				
-			case FADE_IN:
-				players[commandList[i].playerId]->fadeIn(commandList[i].parameter1, secondsToSamples(commandList[i].parameter2));
-				break;
-
-			case FADE_TO:
-				players[commandList[i].playerId]->fadeTo(commandList[i].parameter1, secondsToSamples(commandList[i].parameter2));
-				break;
-
-			case FADE_OUT:
-				players[commandList[i].playerId]->fadeOut(secondsToSamples(commandList[i].parameter1));
-				break;
-
-			case STOP:
-				players[commandList[i].playerId]->stop();
-				break;
-				
-			case LOOP:
-				players[commandList[i].playerId]->setLooping(commandList[i].parameter1==1);
-				break;
-				
-			case VOLUME:
-				players[commandList[i].playerId]->setVolume(commandList[i].parameter1);
-				break;
-				
-			case PAN:
-				players[commandList[i].playerId]->setPan(commandList[i].parameter1);
-				break;
-				
-		}
-	}
-	
-	commandList.clear();
-
-	// MW removed unlock to fix crash, correct?
-	//unlock();
-	 
-	map<PlayerRef, StereoSample*>::iterator it;
-	vector<PlayerRef> playersToDelete;
-	
-	//if(numChannels==2) {
-    for(it = players.begin(); it != players.end(); ++it) {
-        if((*it).second->isPlaying()) {
-            (*it).second->addSamples(samples, length, numChannels);
-        } else {
-            if((*it).second->donePlaying()) { // has it ever played?
-                playersToDelete.push_back((*it).first);
-            }
-        }
-    }
-    
-    // delete any players that have finished playing
-    for(int i = 0; i < playersToDelete.size(); i++) {
-        delete players[playersToDelete[i]];
-        players.erase(playersToDelete[i]);
-    }
-		
-	//}
-
-	int numSamples = length * numChannels;
-
-	// MW removed unlock to fix crash, correct?
-	//lock();
-
-    float saturationCoefficient = 1 + 9*saturationCoefficient;
-    if(saturationCoefficient>10) saturationCoefficient = 10;
-    else if(saturationCoefficient<1) saturationCoefficient = 1;
-
-    float satCoeffMinusOne = (saturationCoefficient-1);
-    
-	for(int i = 0; i <numSamples; i++) {
-        samples[i] *= masterVolume;
-        
-        // do soft sat here maybe.
-        if(softSaturation) {
-            float absX = samples[i]>0?samples[i]:-samples[i];
-            samples[i] = samples[i]*(absX + saturationCoefficient)/(samples[i]*samples[i] + satCoeffMinusOne*absX + 1);
-        }
-        // hard clipping, and clip monitoring
-        if(samples[i]>1) {
-            clipped = true;
-            samples[i] = 1;
-        } else if(samples[i]<-1) {
-            clipped = true;
-            samples[i] = -1;
-        }
-    }
-    
-	unlock();
-}
-
-void audio::setEnabled(bool enabled) {
-	
-    
-	bool _enabled = enabled;
-
-	audioSystem.lock();
-
-	audioSystem.enabled = enabled;
-#ifdef USING_RTAUDIO
-	if(!_enabled && audioSystem.enabled) end();
-	else if(_enabled && !audioSystem.enabled) begin();
-#endif
-	audioSystem.unlock();
-}
-
-/**
- * Loads a sample into RAM, and returns a reference that 
- * can be used for creating sample players
- */
-SampleRef audio::loadSample(string file) {
-	WavFile *wf = new WavFile();
-	if(wf->load(file)) {
-		audioSystem.sampleRefCounter++;
-		audioSystem.audioSamples[audioSystem.sampleRefCounter] = wf;
-		return audioSystem.sampleRefCounter;
-	} else {
-		cout << "Failed to load audio file: "<< file << endl;
-		return 0;
-	}
-}
-
-bool audio::hasClipped() {
-    audioSystem.lock();
-    bool clipped = audioSystem.hasClipped();
-    audioSystem.unlock();
-    return clipped;
-}
-
-
-
-bool audio::isPlaying(PlayerRef playerId) {
-	bool pl = false;
-	audioSystem.lock();
-	if(audioSystem.players.find(playerId)!=audioSystem.players.end()) {
-		pl = audioSystem.players[playerId]->isPlaying();
-	}
-	audioSystem.unlock();
-	return pl;
-}
-
-
-/**
- * Creates a sample player and returns a reference
- * to be used for playing back samples.
- */
-PlayerRef audio::createPlayer(SampleRef sampleId) {
-	// MW required?
-	//audioSystem.lock();
-
-	if(sampleId==0) {
-		cout << "AudioSystem::createPlayer(): Trying to load invalid sample! It probably means the file was not found or is corrupt." << endl;
-		return 0;
-	}
-	
-	if(audioSystem.audioSamples.find(sampleId)==audioSystem.audioSamples.end()) {
-		cout << "AudioSystem::createPlayer(): The sample was not loaded." << endl;
-		return 0;
-	}
-	
-	audioSystem.playerRefCounter++;
-	StereoSample *sample = new StereoSample(audioSystem.audioSamples[sampleId]);
-	audioSystem.players[audioSystem.playerRefCounter] = sample;
-
-	// MW required?
-	//audioSystem.unlock();
-
-	return audioSystem.playerRefCounter;
-}
-
-
-
-
-/**
- * Fades in and plays a sample. Kind of like a soft version of play()
- */
-void audio::fadeIn(PlayerRef playerId, float toVolume, float duration) {
-	audioSystem.addCommand(playerId, FADE_IN, toVolume, duration);
-}
-	
-
-
-/**
- * Sets which channel we should play the audio out of.
- */
-void audio::setChannel(PlayerRef playerId, int channel1, int channel2) {
-	audioSystem.lock();
-	audioSystem.players[playerId]->channel1 = channel1;
-
-	if(channel2!=-1) { // this one's stereo
-		audioSystem.players[playerId]->channel2 = channel2;
-	}
-	
-	audioSystem.unlock();
-}
-		
-
-/**
- * this lets you fade a sound to a certain volume. It doesn't
- * stop playing the sample, just fades the volume.
- */
-void audio::fadeTo(PlayerRef playerId, float toVolume, float duration) {
-	audioSystem.addCommand(playerId, FADE_TO, toVolume, duration);
-}
-	
-
-/**
- * This fades out (and stops) a sample.
- */
-void audio::fadeOut(PlayerRef playerId, float duration) {
-	audioSystem.addCommand(playerId, FADE_OUT, duration);
-}
-	
-	
-bool AudioSystem::hasClipped() {
-    if(clipped) {
-        clipped = false;
-        return true;
-    } else {
-        return false;
-    }
-}

src/AudioEngine/AudioSystem.h

-/*
- *  AudioSystem.h
- *  AudioTest
- *
- *  Created by Marek Bereza on 01/09/2010.
- *
- */
-
-#pragma once
-
-#include <string.h>
-#include <string>
-#include <vector>
-#include <map>
-#include "WavFile.h"
-#include "StereoSample.h"
-#ifdef USING_RTAUDIO
-#include "RtAudio.h"
-#endif
-using namespace std;
-
-
-namespace audio {
-	
-	
-	
-	
-	
-	/** this is the type for the id of a sample in RAM */
-	typedef int SampleRef;
-	
-	/* This references a player that points to a sample in RAM */
-	typedef int PlayerRef;
-		
-	
-	
-	
-	
-	
-	////////////////////////////////////////////////////////////////////////////////////////////////////
-	// 
-	// STARTING/STOPPING
-	// 
-	////////////////////////////////////////////////////////////////////////////////////////////////////
-	
-	
-#ifdef USING_RTAUDIO
-	/** Starts the audio stream. Returns true on success. */
-	bool begin(int audioDeviceId = -1);
-		
-	/** Stops the audio stream. Returns true on success. */
-	bool end();
-#endif
-    
-	/**
-	 * Disposes all the samples in the system, and resets everything. Automatically called on end();
-	 */
-	void reset();
-		
-	
-	
-	
-	
-	
-	
-	
-	////////////////////////////////////////////////////////////////////////////////////////////////////
-	// 
-	// INSTANTIATION OF SAMPLES AND PLAYERS
-	// 
-	////////////////////////////////////////////////////////////////////////////////////////////////////
-	
-	
-	/**
-	 * Loads a sample into RAM, and returns a reference that 
-	 * can be used for creating sample players. Returns 0 if 
-	 * the audio file could not be loaded.
-	 */
-	SampleRef loadSample(string file);
-	
-	/**
-	 * Creates a sample player and returns a reference
-	 * to be used for playing back samples.
-	 */
-	PlayerRef createPlayer(SampleRef sampleId);
-	
-	
-	
-	
-	
-	
-	
-	
-	////////////////////////////////////////////////////////////////////////////////////////////////////
-	// 
-	// PLAYING STUFF
-	// 
-	////////////////////////////////////////////////////////////////////////////////////////////////////
-	
-	
-	/**
-	 * Tells you if a sample is still playing or not
-	 */
-	bool isPlaying(PlayerRef playerId);
-	
-
-	/**
-	 * Starts playing a sample. timeDelay is in seconds and means 
-	 * that the sample will start playing after a delay of timeDelay seconds
-	 */ 
-	void play(PlayerRef playerId, float timeDelay = 0);
-	
-	
-	/**
-	 * Fades in and plays a sample. Kind of like a soft version of play()
-	 */
-	void fadeIn(PlayerRef playerId, float toVolume, float duration);
-	
-	
-	/**
-	 * Stops a sample from playing. When you stop a player, 
-	 * it will delete the player but not the actual sample.
-	 */
-	void stop(PlayerRef playerId);
-	
-	
-	/**
-	 * This fades out (and stops) a sample.
-	 */
-	void fadeOut(PlayerRef playerId, float duration);
-	
-	
-	
-	////////////////////////////////////////////////////////////////////////////////////////////////////
-	// 
-	// MIXING - you can call all these functions at any time while the sample is playing.
-	// 
-	////////////////////////////////////////////////////////////////////////////////////////////////////
-	
-	
-	/**
-	 * Sets which channel we should play the audio out of.
-	 */
-	void setChannel(PlayerRef playerId, int channel1, int channel2 = -1);
-		
-	
-		
-	/**
-	 * Sets whether a sample is looping or not.
-	 */
-	void setLooping(PlayerRef playerId, bool looping);
-	
-	
-	/**
-	 * Sets the volume and pan at the same time
-	 */
-	void setMix(PlayerRef playerId, float volume, float pan);
-	
-	/**
-	 * Sets the pan for an individual sound if it has 2 outputs
-	 */
-	void setPan(PlayerRef playerId, float pan);
-	
-	/**
-	 * Sets the volume for an individual sound
-	 */
-	void setVolume(PlayerRef playerId, float volume);
-	
-	
-	/**
-	 * this lets you fade a sound to a certain volume. It doesn't
-	 * stop playing the sample, just fades the volume.
-	 */
-	void fadeTo(PlayerRef playerId, float toVolume, float duration);
-	
-    
-    /**
-     * This lets you set the output channel of a sound - optionally, 
-     * you can set 2 different channels
-     */
-	void setOutput(PlayerRef playerId, int channel1, int channel2 = -1);
-	
-	
-	////////////////////////////////////////////////////////////////////////////////////////////////////
-	// 
-	// GLOBAL CONTROL
-	// 
-	////////////////////////////////////////////////////////////////////////////////////////////////////
-	
-	
-	/**
-	 * Turns the sound on and off 
-	 */
-	void setEnabled(bool enabled);
-
-	/**
-	 * Sets the master volume for the whole system
-     * You can also set whether to use soft saturation here.
-     * Saturation softness goes from 0 to 1
-     * 
-	 */
-	void setMasterVolume(float volume, bool softSaturation = false, float saturationSoftness = 0.5);
-
-	
-	
-	/**
-     * Returns true if there's been sound clipping since the last time hasClipped() was called.
-     */
-	bool hasClipped();
-	
-	
-	
-	
-	
-	
-	
-	
-	
-	
-	
-	////////////////////////////////////////////////////////////////////////////////////////////////////////
-	// You don't need to know anything beyond here
-	//
-	enum CommandType {
-		PLAY,
-		STOP,
-		LOOP,
-		VOLUME,
-		PAN,
-		FADE_IN,
-		FADE_OUT,
-		FADE_TO,
-        OUTPUT
-	};
-		
-
-	class AudioCommand {
-	public:
-		AudioCommand(PlayerRef _playerId = 0, CommandType _type = PLAY, float _parameter1 = 0, float _parameter2 = 0) {
-			playerId = _playerId;
-			type = _type;
-			parameter1 = _parameter1;
-			parameter2 = _parameter2;
-		}
-
-		PlayerRef playerId;
-		CommandType type ;
-
-		// optional user value
-		float parameter1;
-		float parameter2;
-	};
-
-	class AudioSystem {
-	public:
-		AudioSystem();
-		~AudioSystem();
-		/**
-		 * Gets the audio buffer for playback
-		 */
-		void getSamples(float *samples, int length, int numChannels);
-		
-
-
-		float masterVolume;
-        bool clipped;
-
-        // whether to use soft saturation
-        bool softSaturation;
-
-        // how much saturation.
-        float saturationSoftness;
-        
-        bool hasClipped();
-		void lock();
-		void unlock();
-		
-		bool enabled;
-		
-		/**
-		 * Locks, adds a command then unlocks
-		 */
-		void addCommand(PlayerRef playerId, CommandType type, float parameter = 0, float parameter2 = 0);
-		
-		
-		vector<AudioCommand> commandList;
-		map<SampleRef, WavFile*> audioSamples;
-		map<PlayerRef, StereoSample*> players;
-
-		
-		// increment every time a sample is added
-		SampleRef sampleRefCounter;
-		
-		// increment every time a player is added
-		PlayerRef playerRefCounter;
-#ifdef USING_RTAUDIO
-		// implementation
-		RtAudio *rtAudio;
-#endif
-	};
-	
-	AudioSystem *getAudioSystem();
-}
-

src/AudioEngine/Sample.h

-/**
- * Sample.h
- *
- * Marek Bereza 31/08/2010
- * 
- * Version 3
- *
- * This class relies on the input no. channels to be the output no. channels
- */
-#pragma once
-
-#include "WavFile.h"
-#include <string>
-#include <vector>
-
-using namespace std;
-
-class Playhead {
-public:
-	
-	// can be negative if you want to start playing 
-	// after a certain interval
-	int frame;
-	
-	Playhead(int curr = 0) {
-		frame = curr;
-	}
-
-};
-
-class Sample {
-public:
-
-	Sample() {
-		data = NULL;
-		numChannels = 1;
-		reset();
-
-	}
-	
-	~Sample() {
-		data = NULL;
-	}
-	
-	
-private:
-	void reset() {
-		length = 0;
-		looping = false;
-		multiplay = false;
-		currFrames.clear();
-		hasStartedPlaying = false;
-	}
-	
-	
-public:
-	bool load(string path) {
-		WavFile file;
-		bool loadedSuccessfully = file.load(path);
-		
-		if(loadedSuccessfully) {
-			length = file.getLength();
-			numChannels = file.getNumChannels();
-			data = file.getData();
-		} 
-
-		
-		
-		return loadedSuccessfully;
-	}
-	
-	void setMultiPlay(bool multi) {
-		multiplay = multi;
-	}
-	
-	void setLooping(bool loop) { looping = loop; }
-	
-#define FRAME_BYTE_SIZE (getNumChannels()*sizeof(float))
-	
-	
-	
-	void getSamples(float *samples, int frames) {
-
-		// clear out samples
-		memset(samples, 0, frames*FRAME_BYTE_SIZE);
-		
-
-		if(data!=NULL) {
-			
-			// loop through each playhead
-			for(unsigned int i = 0; i < currFrames.size(); i++) {
-				bool isStillPlaying = accumulateFramesForPlayhead(&currFrames[i], samples, frames);
-				
-				if(!isStillPlaying) {
-					// stop playing
-					currFrames.erase(currFrames.begin()+i);
-					i--;
-				}
-			}
-		}
-	}
-	
-	/**
-	 * Returns true if the sound will still be playing the next time round.
-	 * The idea is that if it's not, it should be removed from the playhead list.
-	 */
-	bool accumulateFramesForPlayhead(Playhead *playhead, float *samples, int frames) {
-		
-		// take up silence before the beginning of the playback of the playhead
-		if(playhead->frame<0) {
-			int numFramesUntilStart = -playhead->frame;
-			// if there's enough silence to fill the whole buffer, just increment the playhead and return
-			if(numFramesUntilStart>=frames) {
-				playhead->frame += frames;
-				return true;
-				
-				// if there's not enough silence at the beginning, advance the 
-				// samples pointer over the silence and update the frame count to
-				// how many frames are left over, and point the playhead to the 
-				// beginning of the file.
-			} else {
-				playhead->frame = 0;
-				samples += numFramesUntilStart*getNumChannels();
-				frames -= numFramesUntilStart;
-			}
-		}
-		// this is where looping will happen
-		
-		if(playhead->frame + frames < length) { // complete copy
-			
-			accumulateFrames(samples, playhead->frame, frames);
-			playhead->frame += frames;
-		} else if(playhead->frame < length) { // at end of sample - part copy
-			
-			// copy the audio
-			int framesToCopy = length - playhead->frame;
-			accumulateFrames(samples, playhead->frame, framesToCopy);
-			
-			if(looping) {
-				
-				
-				if((frames-framesToCopy)>length) {
-					printf("[Sample.h] Error: Sample is too short to loop - the program will probably crash!!!\n");
-				}
-				
-				accumulateFrames(samples+framesToCopy*getNumChannels(), 0, (frames - framesToCopy));
-				playhead->frame = frames - framesToCopy;
-			} else {
-				
-				return false;
-			}
-		}
-		return true;
-	}
-
-	virtual void trigger(int sampleOffset) {
-		hasStartedPlaying = true;
-		// if we're multiplay, push back another playhead
-		if(multiplay) {
-			currFrames.push_back(Playhead(sampleOffset));
-		} else {
-			// otherwise only add one if none exist
-			if(currFrames.size()>0) {
-				currFrames[0].frame = sampleOffset;
-			} else {
-				currFrames.push_back(Playhead(sampleOffset));
-			}
-		}
-	}
-	
-	bool isPlaying() {
-		return currFrames.size()>0;
-	}
-	bool donePlaying() {
-		return hasStartedPlaying && !isPlaying();
-	}
-	
-	void stop() {
-		currFrames.clear();
-	}
-	
-	int getNumChannels() { return numChannels; }
-	int getLength() { return length; }
-	float *getData() { return data; }
-protected:
-	
-	/**
-	 * Copies frames out of the file buffer and into dest
-	 */
-	void accumulateFrames(float *dest, int offset, int len) {
-		offset *= getNumChannels();
-		len *= getNumChannels();
-		for(int i = 0; i < len; i++) {
-			dest[i] += data[i+offset];
-		}
-	}
-	
-	
-	bool hasStartedPlaying;
-	float *data;
-	int numChannels;
-	
-	// if not in multiplay mode, this is the playhead
-	vector<Playhead> currFrames;
-	
-	int length;
-	
-	bool looping;
-	bool multiplay;
-};

src/AudioEngine/StereoSample.cpp

-#include "AudioSystem.h"
-
-#ifdef STEREOSAMPLE_USE_SHARED_BUFFER
-float StereoSample_buffer[BUFF_SIZE];
-#endif
-
-
-void StereoSample::lerpPanQuad() {
-	volume = volume*(1.f-StereoSampleLerpAmt) + targetVolume*StereoSampleLerpAmt;
-	pan = pan*(1.f-StereoSampleLerpAmt) + targetPan*StereoSampleLerpAmt;				
-	width = targetWidth*(1.f-StereoSampleLerpAmt) + targetWidth*StereoSampleLerpAmt;	
-	channelVolumes[0] = getLevel(0.0f, pan, width)*volume;
-	channelVolumes[1] = getLevel(0.3333f, pan, width)*volume;
-	channelVolumes[2] = getLevel(0.6667f, pan, width)*volume;
-	channelVolumes[3] = getLevel(1.0000f, pan, width)*volume;
-}
-
-
-void StereoSample::init() {
-	targetPan = pan = 0.5;
-	targetVolume = volume = 1.0;
-    fadePos = -1;
-    setOutputs(0, 1);
-}
-StereoSample::StereoSample(): Sample() {
-	init();
-}
-	
-StereoSample::StereoSample(StereoSample &other): Sample() {
-	data = other.getData();
-	numChannels = other.getNumChannels();
-	length = other.getLength();
-	init();
-}
-	
-	
-StereoSample::StereoSample(WavFile *wf): Sample() {
-	data = wf->getData();
-	numChannels = wf->getNumChannels();
-	length = wf->getLength();
-	init();
-}
-	
-
-void StereoSample::setWavFile(WavFile *wf) {
-	stop();
-	data = wf->getData();
-	numChannels = wf->getNumChannels();
-	length = wf->getLength();
-	init();
-}
-	
-void StereoSample::setMix(float _volume, float _pan, float _width) {
-	setVolume(_volume);
-	setPan(_pan);
-	setWidth(_width);
-}
-	
-/** Goes from 0 to 1 for left to right */
-void StereoSample::setWidth(float _width) {
-	targetWidth = _width;
-	if(targetWidth<0) targetWidth = 0;
-	if(targetWidth>1) targetWidth = 1;
-}
-void StereoSample::setPan(float _pan) {
-	targetPan = _pan;
-	if(targetPan<0) targetPan = 0;
-	if(targetPan>1) targetPan = 1;
-}
-	
-void StereoSample::setVolume(float vol) {
-	targetVolume = vol;
-}
-	
-	
-#ifndef ABS
-#define ABS(x) (((x) < 0) ? -(x) : (x))
-#endif
-
-#ifndef MAX
-#define MAX(x,y) (((x) > (y)) ? (x) : (y))
-#endif
-
-/**
- * Lets you calculate a volume value 
- * for a speaker positioned at "pos" for a sample positioned at "pan"
- * with a desired width. all params go from 0 - 1
- */
-float StereoSample::getLevel(float pos, float pan, float width) {
-	return 	MAX(1.f - 2.f*width*ABS(pos - pan), 0);
-}
-
-float StereoSample::getFadeVolume() {
-
-    float outVal = fadePos / fadeDuration * (fadeToVolume - fadeFromVolume) + fadeFromVolume;
-    
-    
-    if(fadeToVolume < fadeFromVolume){
-        if( outVal < fadeToVolume ) outVal = fadeToVolume;
-        else if( outVal > fadeFromVolume )outVal = fadeFromVolume;
-    } else {
-        if( outVal > fadeToVolume )outVal = fadeToVolume;
-        else if( outVal < fadeFromVolume )outVal = fadeFromVolume;
-    }
-    return outVal;
-}
-
-
-void StereoSample::addSamplesStereo(float *samples, int length) {
-		
-	if(length>BUFF_SIZE) {
-		printf("Buffer not big enough!!\n");
-		memset(samples, 0, length*2*sizeof(float));
-		return;
-	}
-		
-	// get the samples to work on
-	getSamples(StereoSample_buffer, length);
-	float lerpAmt = 0.05f;
-    
-    if(fadePos>-1) {
-        targetVolume = getFadeVolume();
-        fadePos += length;
-    }
-    
-
-	if(getNumChannels()==1) {
-		for(int i = 0; i < length; i++) {
-            volume = volume*(1.f-lerpAmt) + targetVolume*lerpAmt;
-            
-			pan = pan*(1.f-lerpAmt) + targetPan*lerpAmt;				
-				
-			samples[i*2] += StereoSample_buffer[i]*(1 - pan)*volume;
-			samples[i*2 + 1] += StereoSample_buffer[i]*pan*volume;
-		}
-	} else if(getNumChannels()==2) {
-		for(int i = 0; i < length; i++) {
-				
-			volume = volume*(1.f-lerpAmt) + targetVolume*lerpAmt;
-			pan = pan*(1.f-lerpAmt) + targetPan*lerpAmt;
-				
-			samples[i*2] += StereoSample_buffer[i*2]*(1 - pan)*volume;
-			samples[i*2 + 1] += StereoSample_buffer[i*2+1]*pan*volume;
-		}
-	}
-    if(fadePos>=fadeDuration) {
-        fadePos = -1;
-        if(targetVolume<0.001 && volume<0.001) {
-            stop();
-        }
-    }
-		
-}
-void StereoSample::addSamples(float *samples, int length, int numChannels) {
-    
-	if(length>BUFF_SIZE) {
-		printf("Buffer not big enough!!\n");
-		memset(samples, 0, length*numChannels*sizeof(float));
-		return;
-	}
-    
-	// get the samples to work on
-	getSamples(StereoSample_buffer, length);
-	float lerpAmt = 0.05f;
-    
-    if(fadePos>-1) {
-        targetVolume = getFadeVolume();
-        fadePos += length;
-    }
-    
-    
-    // make sure we don't shoot over the channels
-    channel1 %= numChannels;
-    if(channel2!=-1) channel2 %= numChannels;
-    
-	if(getNumChannels()==1) {
-		for(int i = 0; i < length; i++) {
-            volume = volume*(1.f-lerpAmt) + targetVolume*lerpAmt;
-            
-			pan = pan*(1.f-lerpAmt) + targetPan*lerpAmt;				
-            
-			samples[i*numChannels + channel1] += StereoSample_buffer[i]*(1 - pan)*volume;
-            if(channel2!=-1) 
-                samples[i*numChannels + channel2] += StereoSample_buffer[i]*pan*volume;
-		}
-	} else if(getNumChannels()==2) {
-		for(int i = 0; i < length; i++) {
-            
-			volume = volume*(1.f-lerpAmt) + targetVolume*lerpAmt;
-			pan = pan*(1.f-lerpAmt) + targetPan*lerpAmt;
-            
-			samples[i*numChannels + channel1] += StereoSample_buffer[i*2]*(1 - pan)*volume;
-            
-			if(channel2!=-1) 
-                samples[i*numChannels + channel2] += StereoSample_buffer[i*2+1]*pan*volume;
-		}
-	}
-    
-    
-    
-    
-    
-    
-    
-    
-    
-    
-    
-    
-    
-    
-    if(fadePos>=fadeDuration) {
-        fadePos = -1;
-        if(targetVolume<0.001 && volume<0.001) {
-            stop();
-        }
-    }
-}
-
-
-// fades a sample in over a period of [duration] samples
-// (also starts it playing)
-void StereoSample::fadeIn(float toVolume, int duration) {
-	trigger(0);
-    fadeToVolume = toVolume;
-    fadeFromVolume = 0;
-    targetVolume = 0;
-    volume = 0;
-    fadeDuration = duration;
-    fadePos = 0;
-}
-
-// fades out and stops the sample
-void StereoSample::fadeOut(int duration) {
-	//stop();
-    fadeToVolume = 0;
-    fadeFromVolume = targetVolume;
-    fadeDuration = duration;
-    fadePos = 0;
-}
-
-void StereoSample::fadeTo(float toVolume, int duration) {
-	fadeToVolume = toVolume;
-    fadeFromVolume = targetVolume;
-    fadeDuration = duration;
-    fadePos = 0;
-}
-	
-
-void StereoSample::setOutputs(int channel1, int channel2) {
-    this->channel1 = channel1;
-    this->channel2 = channel2;
-}

src/AudioEngine/StereoSample.h

-/*
- *  StereoSample.h
- *  AudioTest
- *
- *  Created by Marek Bereza on 01/09/2010.
- *
- */
-#pragma once
-
-#include "Sample.h"
-
-
-
-
-#define BUFF_SIZE 16384
-#define StereoSampleLerpAmt 0.05f
-
-// you can either use a shared buffer between all sample instances
-// or one for each sample. - a shared buffer is ok if you're running
-// all instances on a single thread (and much faster if playing lots 
-// of sounds
-#define STEREOSAMPLE_USE_SHARED_BUFFER
-
-
-class StereoSample: public Sample {
-public:
-
-#ifndef STEREOSAMPLE_USE_SHARED_BUFFER
-	float StereoSample_buffer[BUFF_SIZE];
-#endif
-    
-    // index of which channel to play the sound out of
-	int channel1;
-    
-    // optional index for second channel
-	int channel2;
-	
-	// fades a sample in over a period of [duration] samples
-	// (also starts it playing)
-	void fadeIn(float toVolume, int duration);
-
-	// fades out and stops the sample
-	void fadeOut(int duration);
-	
-	void fadeTo(float toVolume, int duration);
-	
-
-	StereoSample();
-	StereoSample(StereoSample &other);
-	StereoSample(WavFile *wf);
-	
-	void setWavFile(WavFile *wf);
-
-	void setMix(float _volume, float _pan, float _width);
-	
-	/** Goes from 0 to 1 for left to right */
-	void setWidth(float _width);
-	void setPan(float _pan);
-	
-	void setVolume(float vol);
-	
-	
-	/**
-	 * Lets you calculate a volume value 
-	 * for a speaker positioned at "pos" for a sample positioned at "pan"
-	 * with a desired width. all params go from 0 - 1
-	 */
-	float getLevel(float pos, float pan, float width);
-
-	void addSamplesStereo(float *samples, int length);
-
-    void addSamples(float *samples, int length, int numChannels);
-    
-	void setOutputs(int channel1, int channel2 = -1);
-	
-private:
-	void lerpPanQuad();
-    float getFadeVolume();
-	void init();
-	float volume;
-	float pan;
-	float width;
-	float channelVolumes[4];
-
-	float targetVolume;
-	float targetPan;
-	float targetWidth;
-    
-    float fadeToVolume;
-    float fadeFromVolume;
-    float fadeDuration;
-    float fadePos;
-};

src/AudioEngine/WavFile.h

-/**
- * WavFile.h
- *
- * Marek Bereza 2010
- * 
- * Originally stolen from somewhere.
- * 
- * Version 4
- */
-#ifndef __WAV_FILE_H__
-#define __WAV_FILE_H__
-#include <stdio.h>
-
-#include <math.h>
-#include <fstream>
-#include <iostream>
-#include <string>
-using namespace std;
-
-#ifndef MIN
-#define MIN(x,y) (((x) < (y)) ? (x) : (y))
-#endif
-
-#define WAVFILE_READ	1
-#define WAVFILE_WRITE	2
-
-class WavFile {
-private:
-	
-	fstream *file;
-	int length;	
-	int channels;
-	float *data;
-public:
-	
-	int getLength() {
-		return length/channels;
-	}
-	int getNumChannels() {
-		return channels;
-	}
-	
-
-	int samplerate;
-	int bitsPerSample;
-
-	int ioMode;
-	
-	void setFormat(int _channels, int _samplerate, int _bitsPerSample) {
-		channels = _channels;
-		samplerate = _samplerate;
-		bitsPerSample = _bitsPerSample;
-	}
-	
-	WavFile() {
-		channels = 1;
-		samplerate = 44100;
-		bitsPerSample = 16;
-		data = NULL;
-		file = NULL;
-		length = 0;
-		ioMode = WAVFILE_READ;
-	}
-	
-	
-	~WavFile() {
-		close();
-		unload();
-	}
-	
-	
-	bool open(string path, int RW) {
-		close();
-		ioMode = RW;
-		if(RW==WAVFILE_WRITE) {
-			
-			
-			close();
-			file = new fstream(path.c_str(), ios::out | ios::binary);
-			
-			writeFormat();
-			return true;
-		} else {
-			printf("WavFile: WAVFILE_READ not implemented yet!\n");
-			return false;
-		}
-	}
-	
-	
-	/**
-	 * This interleaves samples for putting into wav files.
-	 * Give it 2-dim float array (input) and a 1-dim float array (output)
-	 * and a number of samples in each channel and it will fill up the output
-	 */
-	static void interleaveSamples(float **in, float *out, int length) {
-		for(int i = 0; i < length; i++) {
-			out[i*2 + 0] = in[0][i];
-			out[i*2 + 1] = in[1][i];
-		}
-		
-	}
-	
-
-
-
-	void writeFormat() {
-		short myFormat = 1;
-		
-		int mySubChunk1Size = 16;
-		int myByteRate = samplerate * channels * bitsPerSample/8;
-		short myBlockAlign = channels * bitsPerSample/8;
-		
-		int myChunkSize = 36 + length*bitsPerSample/8;
-		int myDataSize = length*bitsPerSample/8;
-		// write the wav file per the wav file format
-		file->seekp (0, ios::beg); 
-		file->write ("RIFF", 4);
-		file->write ((char*) &myChunkSize, 4);
-		file->write ("WAVE", 4);
-		file->write ("fmt ", 4);
-		file->write ((char*) &mySubChunk1Size, 4);
-		file->write ((char*) &myFormat, 2); // should be 1 for PCM
-		file->write ((char*) &channels, 2); // # channels (1 or 2)
-		file->write ((char*) &samplerate, 4); // 44100
-		file->write ((char*) &myByteRate, 4); //
-		file->write ((char*) &myBlockAlign, 2);
-		file->write ((char*) &bitsPerSample, 2); //16
-		file->write ("data", 4);
-		file->write ((char*) &myDataSize, 4);
-	}
-	
-	
-	/**
-	 * Buffer length is nnumber of samples.
-	 */
-	bool write(float *samples, int buffLength) {
-		if(file==NULL) return false;
-		short *buff = new short[buffLength];
-		for(int i = 0; i < buffLength; i++) {
-			buff[i] = (int)(samples[i]*32760.f);
-		}
-		file->write ((char*)buff, buffLength*sizeof(short));
-		length += buffLength;
-		delete [] buff;
-		return true;
-	}
-	
-	
-	
-	void close() {
-		if(file!=NULL) {
-			if(ioMode==WAVFILE_WRITE) {
-				writeFormat();
-			}
-			file->close();
-			file = NULL;
-		}
-	}
-	
-	
-#define WRITE_BUFF_SIZE 256
-	// write out the wav file
-	bool save(string path) {
-		
-		if(data==NULL) return false;
-		
-		open(path.c_str(), WAVFILE_WRITE);
-		
-		short buff[WRITE_BUFF_SIZE];
-		int pos = 0;
-		while(pos<length) {
-			int len = MIN(WRITE_BUFF_SIZE, length-pos);
-			for(int i = 0; i < len; i++) {
-				buff[i] = (int)(data[pos]*32760.f);
-				pos++;
-			}
-			file->write ((char*)buff, len*bitsPerSample/8);
-		}
-		
-		close();
-		return true;
-	}
-	
-	// this gives you data that you have to free yourself
-	float *getData() {
-		return data;
-	}
-	
-	// length is the length in samples, not frames 
-	// - must give malloced memory
-	void setData(float *_data, int _length) {
-		data = _data;
-		length = _length;
-	}
-	
-	/**
-	 * Reads an entire file into the data member of this class. It dynamically
-	 * allocates the memory, and never bothers to delete it (unless you call this
-	 * method again), so take care.
-	 */
-	bool load(string path) {
-		
-		if(file!=NULL) close();
-		file = new fstream(path.c_str(), ios::in | ios::binary);
-		//short myFormat,myBlockAlign;
-		short myBlockAlign;	
-		int mySubChunk1Size,myByteRate;
-		//int myChunkSize,myDataSize;
-		int myChunkSize;
-		short format = 1;
-		file->seekg(4, ios::beg);
-		file->read( (char*) &myChunkSize, 4 ); // read the ChunkSize
-		file->seekg(16, ios::beg);
-		file->read( (char*) &mySubChunk1Size, 4 ); // read the SubChunk1Size
-		file->read( (char*) &format, sizeof(short) ); // read the file format.  This should be 1 for PCM
-		file->read( (char*) &channels, sizeof(short) ); // read the # of channels (1 or 2)
-		file->read( (char*) &samplerate, sizeof(int) ); // read the samplerate
-		file->read( (char*) &myByteRate, sizeof(int) ); // read the byterate
-		file->read( (char*) &myBlockAlign, sizeof(short) ); // read the blockalign
-		file->read( (char*) &bitsPerSample, sizeof(short) ); // read the bitspersample
-		
-		file->seekg(40, ios::beg);
-		file->read( (char*) &length, sizeof(int) ); // read the size of the data
-		
-		length /= sizeof(short);
-		if(bitsPerSample!=16 || length<=0 || format!=1) {
-			return false;
-		}
-		
-		// read the data chunk
-		short *rawData = new short[length];
-		file->seekg(44, ios::beg);
-		file->read((char*)rawData, length*sizeof(short));
-		file->close(); // close the input file
-		
-		unload();
-		// bytes to shorts
-		data = new float[length];
-		printf("Allocated data\n");
-		for(int i = 0; i < length; i++) {
-			data[i] = ((float)rawData[i])/32767.f;
-		}
-		delete rawData;
-		
-		close();
-		
-		return true; // this should probably be something more descriptive
-	}
-	void unload() {
-		if(data!=NULL) free(data);
-		data = NULL;
-	}
-};
-
-#endif // __WAV_FILE_H__

src/AudioEngine/core/AudioSystem.cpp

+/*
+ *  AudioSystem.cpp
+ *  AudioTest
+ *
+ *  Created by Marek Bereza on 01/09/2010.
+ *  Copyright 2010 Marek Bereza. All rights reserved.
+ *
+ */
+
+
+#include "AudioSystem.h"
+#ifdef WIN32
+#include <Windows.h>
+#include <process.h>
+CRITICAL_SECTION  critSec;  	//same as a mutex
+#else
+#include <pthread.h>
+#include <semaphore.h>
+pthread_mutex_t  myMutex;
+#endif
+
+
+
+
+
+using namespace audio;
+
+AudioSystem audioSystem;
+
+AudioSystem *audio::getAudioSystem() {
+	return &audioSystem;
+}
+
+#ifdef USING_RTAUDIO
+
+// audio callback
+int audioCallback( void *outputBuffer, void *inputBuffer, unsigned int nBufferFrames,
+         double streamTime, RtAudioStreamStatus status, void *userData ) {
+			   
+  float *buffer = (float *) outputBuffer;
+  AudioSystem *as = (AudioSystem *) userData;
+
+  as->getSamples(buffer, nBufferFrames, 2);
+
+  return 0;
+}
+#endif
+
+AudioSystem::AudioSystem() {
+	sampleRefCounter = 0;
+	playerRefCounter = 0;
+	masterVolume = 1.0;
+    softSaturation = false;
+    saturationSoftness = 0.5;
+#ifdef USING_RTAUDIO
+	rtAudio = NULL;
+#endif
+	enabled = true;
+#ifdef WIN32 
+	InitializeCriticalSection(&critSec); 
+#else 
+	pthread_mutex_init(&myMutex, NULL); 
+#endif 
+	
+}
+
+
+AudioSystem::~AudioSystem() {
+
+#ifndef WIN32 
+	pthread_mutex_destroy(&myMutex); 
+#endif 
+}
+
+void audio::setMasterVolume(float volume, bool softSaturation, float saturationSoftness) {
+	if(volume>1.0) volume = 1.0;
+	if(volume<0) volume = 0;
+	audioSystem.lock();
+	audioSystem.masterVolume = volume;
+    audioSystem.softSaturation = softSaturation;
+    audioSystem.saturationSoftness = saturationSoftness;
+	audioSystem.unlock();
+}
+
+#ifdef USING_RTAUDIO
+bool audio::begin(int deviceId) {
+
+	audioSystem.lock();
+	if(!audioSystem.enabled) return false;
+	audioSystem.unlock();
+		
+	if(audioSystem.rtAudio!=NULL) delete audioSystem.rtAudio;
+
+	audioSystem.rtAudio = new RtAudio();
+
+
+	unsigned int devices = audioSystem.rtAudio->getDeviceCount();
+	cout << "found " << devices << " audio devices"<<endl;
+	
+	if(deviceId==-1) deviceId = audioSystem.rtAudio->getDefaultOutputDevice();
+	
+	string currDeviceName = "";
+	// Scan through devices for various capabilities
+	RtAudio::DeviceInfo info;
+	for ( unsigned int i=0; i<devices; i++ ) {
+		
+		info = audioSystem.rtAudio->getDeviceInfo( i );
+		if(deviceId==i) {
+			currDeviceName = info.name;
+		}
+		if ( info.probed == true ) {
+			// Print, for example, the maximum number of output channels for each device
+			std::cout << "device = " << i << "  - " << info.name;
+			std::cout << ": maximum output channels = " << info.outputChannels << "\n";
+
+			
+			
+    }
+  }
+
+
+	
+	cout << "Using device (" << deviceId << ") - " << currDeviceName << endl; 
+	RtAudio::StreamParameters parameters;
+	parameters.deviceId = deviceId;
+	parameters.nChannels = 2;
+	parameters.firstChannel = 0;
+	unsigned int sampleRate = 44100;
+	unsigned int bufferFrames = 1024; // 256 sample frames
+		
+
+	try {
+		audioSystem.rtAudio->openStream( &parameters, NULL, RTAUDIO_FLOAT32,
+                   sampleRate, &bufferFrames, &audioCallback, (void *)&audioSystem );
+		audioSystem.rtAudio->startStream();
+		return true;
+	} catch ( RtError& e ) {
+	    cout << "Couldn't connect to device " << endl;
+	   	e.printMessage();
+	    return false;
+	}
+}
+
+bool audio::end() {
+	audioSystem.lock();
+	if(!audioSystem.enabled) return false;
+	audioSystem.unlock();
+	try {
+
+		if ( audioSystem.rtAudio->isStreamOpen() ) {
+
+			
+			audioSystem.rtAudio->closeStream();
+			//audioSystem.rtAudio->abortStream();
+			
+			cout << "Closed audio successfully" << endl;
+			// kills the stream immediately - we need to do this because the destructor comes immediately after.
+			
+			reset();
+		}
+		return true;
+	} catch(RtError& e) {
+		cout << "Couldn't close device" << endl;
+		e.printMessage();
+	}
+	return false;
+}
+
+
+#endif
+void AudioSystem::lock() {
+#ifdef WIN32 
+	EnterCriticalSection(&critSec); 
+#else 
+	pthread_mutex_lock(&myMutex); 
+#endif 
+}
+
+void AudioSystem::unlock() {
+#ifdef WIN32 
+	LeaveCriticalSection(&critSec); 
+#else 
+	pthread_mutex_unlock(&myMutex); 
+#endif 
+}
+
+void audio::reset() {
+	audioSystem.commandList.clear();
+
+	map<SampleRef, WavFile*>::iterator a;
+	for(a = audioSystem.audioSamples.begin(); a != audioSystem.audioSamples.end(); a++) {
+		delete (*a).second;
+	}
+	audioSystem.audioSamples.clear();
+
+	map<PlayerRef, StereoSample*>::iterator b;
+	for(b = audioSystem.players.begin(); b != audioSystem.players.end(); b++) {
+		delete (*b).second;
+	}
+	audioSystem.players.clear();
+}
+
+void audio::play(PlayerRef playerId, float timeDelay) {
+	
+	audioSystem.addCommand(playerId, PLAY, timeDelay);
+
+}
+
+
+/**
+ * Stops a sample from playing
+ */
+void audio::stop(PlayerRef playerId) {
+	audioSystem.addCommand(playerId, STOP);
+}
+
+
+/**
+ * Sets whether a sample is looping or not.
+ */
+void audio::setLooping(PlayerRef playerId, bool looping) {
+	audioSystem.addCommand(playerId, LOOP, looping ? 1.0f : 0.0f);
+}
+
+void audio::setMix(PlayerRef playerId, float volume, float pan) {
+	audioSystem.lock();
+	audioSystem.commandList.push_back(AudioCommand(playerId, VOLUME, volume));
+	audioSystem.commandList.push_back(AudioCommand(playerId, PAN, pan));
+	audioSystem.unlock();
+}
+
+
+void audio::setPan(PlayerRef playerId, float pan) {
+	audioSystem.addCommand(playerId, PAN, pan);
+}
+
+void audio::setVolume(PlayerRef playerId, float volume) {
+	audioSystem.addCommand(playerId, VOLUME, volume);
+}
+
+void audio::setOutput(PlayerRef playerId, int channel1, int channel2) {
+    audioSystem.addCommand(playerId, OUTPUT, channel1, channel2);
+}
+
+
+void AudioSystem::addCommand(PlayerRef playerId, CommandType type, float parameter1, float parameter2) {
+	//lock();
+	commandList.push_back(AudioCommand(playerId, type, parameter1, parameter2));
+	//unlock();
+}
+
+int secondsToSamples(float seconds) {
+	float samples = 44100.f*seconds;
+	return (int) samples;
+}
+
+void AudioSystem::getSamples(float *samples, int length, int numChannels) {
+
+	memset(samples, 0, numChannels*sizeof(float)*length);
+	
+	lock();
+	if(!enabled) return;
+	for(unsigned int i = 0; i < commandList.size(); i++) {
+		if(commandList[i].playerId==0) {
+			cout << "Trying to play unallocated sample!!" << endl;
+			continue;
+		}
+		
+		
+		switch(commandList[i].type) {
+				
+			case PLAY:
+				players[commandList[i].playerId]->trigger(-secondsToSamples(commandList[i].parameter1));
+				break;
+            case OUTPUT:
+                players[commandList[i].playerId]->setOutputs(commandList[i].parameter1, commandList[i].parameter2);
+                break;
+				
+			case FADE_IN:
+				players[commandList[i].playerId]->fadeIn(commandList[i].parameter1, secondsToSamples(commandList[i].parameter2));
+				break;
+
+			case FADE_TO:
+				players[commandList[i].playerId]->fadeTo(commandList[i].parameter1, secondsToSamples(commandList[i].parameter2));
+				break;
+
+			case FADE_OUT:
+				players[commandList[i].playerId]->fadeOut(secondsToSamples(commandList[i].parameter1));
+				break;
+
+			case STOP:
+				players[commandList[i].playerId]->stop();
+				break;
+				
+			case LOOP:
+				players[commandList[i].playerId]->setLooping(commandList[i].parameter1==1);
+				break;
+				
+			case VOLUME:
+				players[commandList[i].playerId]->setVolume(commandList[i].parameter1);
+				break;
+				
+			case PAN:
+				players[commandList[i].playerId]->setPan(commandList[i].parameter1);
+				break;
+				
+		}
+	}
+	
+	commandList.clear();
+
+	// MW removed unlock to fix crash, correct?
+	//unlock();
+	 
+	map<PlayerRef, StereoSample*>::iterator it;
+	vector<PlayerRef> playersToDelete;
+	
+	//if(numChannels==2) {
+    for(it = players.begin(); it != players.end(); ++it) {
+        if((*it).second->isPlaying()) {
+            (*it).second->addSamples(samples, length, numChannels);
+        } else {
+            if((*it).second->donePlaying()) { // has it ever played?
+                playersToDelete.push_back((*it).first);
+            }
+        }
+    }
+    
+    // delete any players that have finished playing
+    for(int i = 0; i < playersToDelete.size(); i++) {
+        delete players[playersToDelete[i]];
+        players.erase(playersToDelete[i]);
+    }
+		
+	//}
+
+	int numSamples = length * numChannels;
+
+	// MW removed unlock to fix crash, correct?
+	//lock();
+
+    float saturationCoefficient = 1 + 9*saturationCoefficient;
+    if(saturationCoefficient>10) saturationCoefficient = 10;
+    else if(saturationCoefficient<1) saturationCoefficient = 1;
+
+    float satCoeffMinusOne = (saturationCoefficient-1);
+    
+	for(int i = 0; i <numSamples; i++) {
+        samples[i] *= masterVolume;
+        
+        // do soft sat here maybe.
+        if(softSaturation) {
+            float absX = samples[i]>0?samples[i]:-samples[i];
+            samples[i] = samples[i]*(absX + saturationCoefficient)/(samples[i]*samples[i] + satCoeffMinusOne*absX + 1);
+        }
+        // hard clipping, and clip monitoring
+        if(samples[i]>1) {
+            clipped = true;
+            samples[i] = 1;
+        } else if(samples[i]<-1) {
+            clipped = true;
+            samples[i] = -1;
+        }
+    }
+    
+	unlock();
+}
+
+void audio::setEnabled(bool enabled) {
+	
+    
+	bool _enabled = enabled;
+
+	audioSystem.lock();
+
+	audioSystem.enabled = enabled;
+#ifdef USING_RTAUDIO
+	if(!_enabled && audioSystem.enabled) end();
+	else if(_enabled && !audioSystem.enabled) begin();