Commits

Marek Bereza committed ec19421

Got a basic xml format going

Comments (0)

Files changed (13)

Binary file modified.
 \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 \
+\f0\fs24 \cf0 clean up players in Personality\
+\
+create players \
 	LoopFader\
 		- control range - modulation frequency\
 RandomSoundEmitter\
 \pard\tx566\tx1133\tx1700\tx2267\tx2834\tx3401\tx3968\tx4535\tx5102\tx5669\tx6236\tx6803\pardirnatural
 \cf0 xml files\
 personality class\
-\
+per channel volumes\
 \
 \
 // maybes\

audioOutputExample.xcodeproj/project.pbxproj

 		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>"; };
+		EA11C40B13E847C000D41E78 /* Looper.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Looper.h; sourceTree = "<group>"; };
+		EA11C40C13E8503700D41E78 /* Fader.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Fader.h; sourceTree = "<group>"; };
 /* End PBXFileReference section */
 
 /* Begin PBXFrameworksBuildPhase section */
 				EA11C3F313E8346600D41E78 /* Personality.cpp */,
 				EA11C3F413E8346600D41E78 /* Personality.h */,
 				EA11C3F613E8346600D41E78 /* Player.h */,
+				EA11C40B13E847C000D41E78 /* Looper.h */,
 				EA11C40A13E838DE00D41E78 /* OneShot.h */,
+				EA11C40C13E8503700D41E78 /* Fader.h */,
 			);
 			path = player;
 			sourceTree = "<group>";

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" />
+
+<!--
+ This is a oneshot sample player - i.e. it plays sounds from beginning to end randomly
+ 
+ output1 is the first output channel
+ output2 (optional) is the second output channel
+ minInterval and maxInterval are the minimum and maximum amount of time between one sound and the next (in seconds)
+ minVolume and maxVolume are the range of volumes you can have (default is always full volume)
+ -->
+
+<!--
+<oneshot output1="0" output2="1" minInterval="2" maxInterval="4" minVolume="0.2" maxVolume="0.8" minPan="0" maxPan="0">
+    <sound file="bird1.wav" />
+    <sound file="bird2.wav" />
+    <sound file="bird3.wav" />
+    <sound file="bird4.wav" />
+    <sound file="bird5.wav" />
 </oneshot>
+-->
+<!--
+ In this example of a oneshot, instead of listing out each file, you can just specify a folder
+ -->
+<oneshot output1="0" output2="1" minInterval="0.05" maxInterval="0.1" minPan="0.5" maxPan="0.7" minVolume="0.0" maxVolume="1.0">
+    <sound folder="drops/glass/" />
+</oneshot>
+<!--
+<oneshot output1="0" output2="1" minInterval="0.01" maxInterval="0.1" minPan="0.1" maxPan="0.3" minVolume="0.3" maxVolume="1">
+    <sound folder="drops/wood/" />
+</oneshot>
+
+-->
+<!--
+ This is a loop player. It lets you specify a bunch of different loops and how to modulate them.
+ -->
+<!--
+<looper output1="0" output2="1">
+    <loop file="water1.wav" />
+    <loop file="water2.wav" />
+    <loop file="water3.wav" />
+    <loop file="water4.wav" />
+</looper>
+-->

src/AudioEngine/core/AudioSystem.cpp

 }
 
 void audio::play(PlayerRef playerId, float timeDelay) {
-	
+	if(playerId==0) {
+        printf("Trying to paly a zero\n");
+    }
 	audioSystem.addCommand(playerId, PLAY, timeDelay);
 
 }
 	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;
+		if(commandList[i].playerId==0 || players.find(commandList[i].playerId)==players.end()) {
+            printf("Trying to %d an unallocated sample!!\n", commandList[i].type);
+
 			continue;
 		}
 		
 	audioSystem.unlock();
 }
 
+
 /**
  * Loads a sample into RAM, and returns a reference that 
  * can be used for creating sample players
  */
 SampleRef audio::loadSample(string file) {
+
+    // don't load if we've already loaded
+    if(audioSystem.loadedSamples.find(file)!=audioSystem.loadedSamples.end()) {
+        return audioSystem.loadedSamples[file];
+    }
+    
+    
 	WavFile *wf = new WavFile();
 	if(wf->load(file)) {
 		audioSystem.sampleRefCounter++;
 		audioSystem.audioSamples[audioSystem.sampleRefCounter] = wf;
+        audioSystem.loadedSamples[file] = audioSystem.sampleRefCounter;
 		return audioSystem.sampleRefCounter;
 	} else {
 		cout << "Failed to load audio file: "<< file << endl;

src/AudioEngine/core/AudioSystem.h

 	////////////////////////////////////////////////////////////////////////////////////////////////////////
 	// You don't need to know anything beyond here
 	//
+    
+    SampleRef getSampleByFileName(string file);
+    
 	enum CommandType {
 		PLAY,
 		STOP,
 		map<SampleRef, WavFile*> audioSamples;
 		map<PlayerRef, StereoSample*> players;
 
-		
+
+        // convenience lookup map to see if we've already loaded an audio file.
+		map<string,SampleRef> loadedSamples;
+        
 		// increment every time a sample is added
 		SampleRef sampleRefCounter;
 		

src/AudioEngine/core/WavFile.h

 		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;
 		}

src/AudioEngine/player/Fader.h

+//
+//  Fader.h
+//  audioOutputExample
+//
+//  Created by Marek Bereza on 02/08/2011.
+//
+
+#pragma once
+#include "ofMain.h"
+
+/**
+ * Simple class that manages the timing of a fade between values.
+ * A little bit like a simple tweener.
+ */
+class Fader {
+public:
+    
+    void setValue(float value) {
+        fadeFrom = value;
+        fadeTo = value;
+        fadeDuration = 0;
+        fadeStart = 0;
+    }
+    
+    void fadeTo(float value, float duration) {
+        fadeFrom = getValue();
+        fadeTo = value;
+        fadeStart = ofGetElapsedTimef();
+        fadeDuration = duration;
+        
+    }
+    
+    float getValue() {
+        float t = ofGetElapsedTimef();
+        if(t>fadeStart+fadeDuration) return fadeTo; // a little bit faster than just calling ofMap all the time.
+        return ofMap(t - fadeStart, 0, fadeDuration, fadeFrom, fadeTo, true);
+    }
+    
+private:
+    float fadeFrom;
+    float fadeTo;
+    float fadeStart;
+    float fadeDuration;
+};

src/AudioEngine/player/Looper.h

+//
+//  Looper.h
+//  audioOutputExample
+//
+//  Created by Marek Bereza on 02/08/2011.
+//
+
+#pragma once
+
+#include "Player.h"
+
+class Looper: public Player {
+public: 
+    void loadFromXml(ofxXmlSettings &xml, string tagName, int which) {
+        xml.pushTag(tagName, which);
+        
+        loadLoops(xml);
+        xml.popTag();
+    }
+    
+    
+    
+    
+
+    void loadLoops(ofxXmlSettings &xml) {
+        int numLoops = xml.getNumTags("loop");
+        
+        // load each sound in the xml
+        for(int i = 0; i < numLoops; i++) {
+            
+            // test to see if we're loading files or folders
+            string filePath = ofToDataPath(xml.getAttribute("loop", "file", "", i));
+            loops.push_back(audio::loadSample(filePath));
+        }
+    }
+    
+    
+private:
+    vector<audio::SampleRef> loops;
+    
+    // which speakers to play the sound out of
+    int output1;
+    int output2;
+
+};

src/AudioEngine/player/OneShot.h

 class OneShot: public Player {
 public:
     virtual void loadFromXml(ofxXmlSettings &xml, string tagName, int which) {
+        
+        // find out which outputs we want
+        output1 = xml.getAttribute(tagName, "output1",  0, which);
+        output2 = xml.getAttribute(tagName, "output2", -1, which);
+        // default channels are 0 and -1 (i.e. just 0 - minus one is no speaker)
+        
+        minInterval = xml.getAttribute(tagName, "minInterval", 2.f, which);
+        maxInterval = xml.getAttribute(tagName, "maxInterval", 3.f, which);
+        
+        minVolume = xml.getAttribute(tagName, "minVolume", 1.f, which);
+        maxVolume = xml.getAttribute(tagName, "maxVolume", 1.f, which);
+        
+
+        minPan = xml.getAttribute(tagName, "minPan", 0.f, which);
+        maxPan = xml.getAttribute(tagName, "maxPan", 1.f, which);
+
+        // the pan should be 0 when mono
+        if(output2==-1) minPan = maxPan = 0;        
+
+        
+        
         xml.pushTag(tagName, which);
+        loadSounds(xml);
+        
+        // remember to restore the xml
+        xml.popTag();
+    }
+    
+    
+    
+    void loadSounds(ofxXmlSettings &xml) {
         int numSounds = xml.getNumTags("sound");
         
         // load each sound in the xml
         for(int i = 0; i < numSounds; i++) {
             
-            string filePath = ofToDataPath(xml.getAttribute("sound", "file", "", i));
             
-            sounds.push_back(audio::loadSample(filePath));
+            // test to see if we're loading files or folders
+            if(xml.attributeExists("sound", "file", i)) {
+                string filePath = ofToDataPath(xml.getAttribute("sound", "file", "", i));
+                sounds.push_back(audio::loadSample(filePath));
+            } else if(xml.attributeExists("sound", "folder", i)) {
+                ofDirectory dir;
+                dir.allowExt("wav");
+                int numEntries = dir.listDir(xml.getAttribute("sound", "folder", "", i));
+                for(int j = 0; j < numEntries; j++) {
+                    string filePath = ofToDataPath(dir.getPath(j));
+                    sounds.push_back(audio::loadSample(filePath));
+                }
+                
+            }
         }
-        
-        // remember to restore the xml
-        xml.popTag();
     }
     
-    void start() {
+    
+    void fadeIn(float duration) {
+        lastTimePlayedASound = ofGetElapsedTimef();
+        interval = minInterval;
     }
     
     
-    void stop() {
-        
+    void fadeOut(float duration) {
     }
     
     void tick() {
+        // if we're due to play a sound, create a new interval
+        if(ofGetElapsedTimef() - lastTimePlayedASound>interval) {
+            interval = ofRandom(minInterval, maxInterval);
+            lastTimePlayedASound = ofGetElapsedTimef();
+            playRandomSound();
+        }
+    }
+    
+    void playRandomSound() {
+        // chose a random sample to play
+		int whichSoundToPlay = rand()%sounds.size();
+		
+		
+		// create a player for it (gets auto-destroyed when it finishes playing)
+		audio::PlayerRef player = audio::createPlayer(sounds[whichSoundToPlay]);
         
+        // assign its outputs
+        if(output2==-1) {
+            audio::setOutput(player, output1, -1);
+        } else {
+            audio::setOutput(player, output1, output2);
+        }
+        
+        // set the volume and pan
+        audio::setMix(player, ofRandom(minVolume, maxVolume), ofRandom(minPan, maxPan));
+        
+        // jitter the delay in playing the sound file a little bit.
+		audio::play(player, ofRandom(0, 0.05));
     }
+    
 private:
     vector<audio::SampleRef> sounds;
+    
+    // which speakers to play the sound out of
+    int output1;
+    int output2;
+    
+    // how often to randomly play a sound
+    float minInterval;
+    float maxInterval;
+    
+    float minVolume;
+    float maxVolume;
+    
+    float minPan;
+    float maxPan;
+    
+    // currently, how long to wait till playing the next sound
+    float interval;
+    
+    float lastTimePlayedASound;
 };

src/AudioEngine/player/Personality.cpp

 
 #include "Personality.h"
 #include "OneShot.h"
+#include "Looper.h"
 
 /**
  * This loads in all the sounds to ram. Any 
     ofxXmlSettings xml;
     xml.loadFile(xmlFile);
     loadType("oneshot", xml);
-    
+    loadType("looper", xml);
 }
 
 
     for(int i = 0; i < numOfThisType; i++) {
         Player *p = createType(type);
         p->loadFromXml(xml, type, i);
+        players.push_back(p);
     }
 }
 
 Player *Personality::createType(string type) {
     if(type=="oneshot") {
         return new OneShot();
+    } else if(type=="looper") {
+        return new Looper();
     }
 }
 /**
  * This starts the personality playing.
  */
-void Personality::start() {
+void Personality::fadeIn(float duration) {
     for(int i = 0; i < players.size(); i++) {
-        players[i]->start();
+        players[i]->fadeIn(duration);
     }
 }
 
 /**
  * This fades out the personality.
  */
-void Personality::stop() {
+void Personality::fadeOut(float duration) {
     for(int i = 0; i < players.size(); i++) {
-        players[i]->stop();
+        players[i]->fadeOut(duration);
     }
 }
 

src/AudioEngine/player/Personality.h

      */
     void loadFromXml(string xmlFile);
     
+    
     /**
      * This starts the personality playing.
      */
-    void start();
+    void fadeIn(float duration = 1);
     
     /**
      * This fades out the personality.
      */
-    void stop();
+    void fadeOut(float duration = 1);
     
     /**
      * This ticks over the sequencing part

src/AudioEngine/player/Player.h

      */
     virtual void loadFromXml(ofxXmlSettings &xml, string tagName, int which) {}
     
-    virtual void start() {}
+    virtual void fadeIn(float duration) {}
     
     
-    virtual void stop() {}
+    virtual void fadeOut(float duration) {}
     
     /** Ticks the internal sequencing. */
     virtual void tick() {}
 void testApp::setup(){
     
     personality.loadFromXml("personality1.xml");
-	audio::setMasterVolume(0.2, true);
+	audio::setMasterVolume(0.8, true);
     ofSetFrameRate(60);
     soundStream.setup(this, 2, 0, 44100, 256, 1);
- 
+
 }
 
 
 //--------------------------------------------------------------
 void testApp::update(){
-   
+    personality.tick();
 }
 
 
 
 //--------------------------------------------------------------
 void testApp::mousePressed(int x, int y, int button){
-  
+    personality.fadeIn();
     
 }
 
 
 //--------------------------------------------------------------
 void testApp::mouseReleased(int x, int y, int button){
+    personality.fadeOut();
 }
 
 //--------------------------------------------------------------