Skip to content
Arthur Nishimoto edited this page May 11, 2015 · 17 revisions

Last revision: ver. 5.3 - 5 March 2014

The Omicron Sound API allows CAVE2 developers a simple way to trigger, place, and update sounds in virtual space. The API sends simple Open Sound Control (OSC) messages to the CAVE2 Audio Server developed by JD Pirtle.

The coordinate system used by the sound API is the same as the tracker: origin on the floor at the center of CAVE2, Y-up. Positions are stored as vector3 floats in meters. Orientations in quaternions.

Currently the CAVE2 Audio Server accepts 48 kHz wav files. For sounds to correctly play in 3D space using the play() function, the sound file must only have a single audio track (mono). Stereo sound files using playStereo() can have two (stereo) audio tracks.

The CAVE2 Tracking/Speaker Coordinate System


class SoundManager

Provides basic management of the sound server and sound objects. Uses the Ultra minimalistic OSC library (http://gruntthepeon.free.fr/oscpkt/).

Methods

Method(s) Description Associated OSC Messages
connectToServer(IP, port) Connects to a sound server at the specified IP address and port.
startSoundServer() Starts the sound server and loads the default synthdefs. /startServer /loadSynth /loadStereoSynth
stopSoundServer() Shuts down the sound server. /killServer
getEnvironment(), setEnvironment(SoundEnvironment) Gets and sets the current sound environment.
sendOSCMessage(Message) Sends an OSC message to the server.
showDebugInfo(bool) Toggles console display of all debugging messages.
isDebugEnabled() Returns whether displaying debugging information to the console has been enabled.
getServerVolume(), setServerVolume(value) Gets and sets the global sound server volume (-30 to 8, CAVE2 Omicron default is -16). /serverVol (value)
getSoundLoadWaitTime(), setSoundLoadWaitTime(value) Gets and sets the delay in milliseconds after each loadSoundFromFile() call (default: 200)

class SoundEnvironment

The sound environment class provides a set of default sound parameters used for all sound objects it creates.

Methods

Method(s) Description Associated OSC Messages
Environment Management
stopAllSounds() Stops any currently playing sounds in the current sound environment /freeNode (nodeID)
cleanupAllSounds() Unloads all sounds in the current sound environment. /freeBuf (bufferID)
getSoundManager()
getAssetDirectory(), setAssetDirectory(path) Gets and sets the default directory path for all created sounds.
getRoomSize(), setRoomSize(value) Gets and sets the default reverb room size for all created sounds as a normalized float (0.0-1.0) /setReverb (nodeID, wetness, roomSize)
getWetness(), setWetness(value) Gets and sets the default reverb wetness/dryness for all created sounds as a normalized float (0.0-1.0) /setReverb (nodeID, wetness, roomSize)
Sound Management
loadSoundFromFile(name, fileName) Creates an new sound object with the given name and path to the sound file. /loadBuffer (See Sound::loadFromFile)
createInstance(sound) Creates an new sound instance from the given sound object.
getListenerPosition(), setListenerPosition(pos) Gets and sets the listener position. This corresponds to CAVE2's navigated position in the virtual space (meters, Y up).
getListenerOrientation(), setListenerOrientation(orientation) Gets and sets the listener orientation. This corresponds to CAVE2's navigated position in the virtual space (Quaternion).
getUserPosition(), setUserPosition(pos) Gets and sets the user position. This corresponds to tracked user's head position in tracker space (meters, Y up). Not fully supported yet - will assume user is at origin
getUserOrientation(), setUserOrientation(orientation) Gets and sets the user orientation. This corresponds to tracked user's head orientation in tracker space (Quaternion).
worldToLocalPosition(position) Convert a position from virtual space to local tracker/speaker space based on the listener's current orientation and position. SoundInstance uses this automatically unless setLocalPosition() is used instead of setPosition()
localtoWorldPosition(position) Convert a position from local tracker/speaker to virtual space space based on the listener's current orientation and position.
getVolumeScale(), setVolumeScale(volume) Gets and sets the normalized (0.0-1.0) volume scale multiplied to every sound instance associated with the environment. /setVol (instanceID, volume)
isForceCacheOverwriteEnabled(), setForceCacheOverwrite(value) Gets and sets if loaded sounds should overwrite existing files on the sound server.
getSoundLoadWaitTime(), setSoundLoadWaitTime(value) Gets and sets the delay in milliseconds after each loadSoundFromFile() call (default: 200)

class Sound

A sound object storing the bufferID, filepath to the sound, and the default sound properties. These correspond to Supercollider buffers. Sound objects will use the same room size and wetness values as the current environment by default. If these parameters are manually changed (i.e. setRoomSize() is used) the sound will use those values instead until resetToEnvironmentParameters() is called.

Methods

Method(s) Description Associated OSC Messages
loadFromFile(path) Loads a sound file withe the given path. /loadBuffer (bufferID,path)
getDefaultRoomSize(), setDefaultRoomSize(value) Gets and sets the default reverb room size for this sound as a normalized float (0.0-1.0)
getDefaultWetness(), setDefaultWetness(value) Gets and sets the default reverb wetness/dryness for this sound as a normalized float (0.0-1.0)
getDefaultWidth(), setDefaultWidth(value) Gets and sets the default speaker width for this sound (1-20)
getDefaultPitch(), setDefaultPitch(value) Gets and sets the default pitch for this sound (1.0 normal, 2.0 one octave up, 0.5 one octave down, -1 backwards)
resetToEnvironmentParameters() Resets this sound objects environment parameters (room size and reverb) to the environment settings
isUsingEnvironmentParameters() Returns false if the environment paremeters for this sound was manually changed using setRoomSize() or setWetness()

The following is a snippet of the soundtest.cpp application which is included within Omicron. In you use the Omicron SoundAPI in conjunction with OmegaLib's rendering framework, you only need to get the sound environment and load sounds from it. All SoundManager initializations and setting the listener and user positions it provided by the OmegaLib engine class. For using the Omicron SoundAPI functions using Omegalib's python interface, see OmegaPythonReference.

Sound setup outside of Omegalib:

	SoundManager* soundManager;
	SoundEnvironment* env;
	Sound* sound;
	Sound* music;
	
	SoundTest()
	{
		soundManager = new SoundManager("supercolliderIP",57120);

		// Delay for loadSoundFromFile()
		// Necessary if creating a new SoundInstance immediatly after calling loadSoundFromFile()
		// Default is 500, although may need to be adjusted depending on the sound server
		soundManager->setSoundLoadWaitTime(500);

		// Show additional debug info related to Omicron<->SuperCollider messages
		//soundManager->showDebugInfo(true);

		// Start the sound server (if not already started)
		soundManager->startSoundServer();
		
		// Get default sound environment
		env = soundManager->getSoundEnvironment();

		
		ofmsg("SoundTest: Checking if sound server is ready at %1% on port %2%... (Waiting for %3% seconds)", %soundServerIP %soundServerPort %(soundServerCheckDelay/1000));

		bool serverReady = true;
		timeb tb;
		ftime( &tb );
		int curTime = tb.millitm + (tb.time & 0xfffff) * 1000;
		int lastSoundServerCheck = curTime;

		while( !soundManager->isSoundServerRunning() )
		{
			timeb tb;
			ftime( &tb );
			curTime = tb.millitm + (tb.time & 0xfffff) * 1000;
			int timeSinceLastCheck = curTime-lastSoundServerCheck;

			if( timeSinceLastCheck > soundServerCheckDelay )
			{
				omsg("SoundTest: Failed to start sound server. Sound disabled.");
				serverReady = false;
				break;
			}
		}

		// If this is not set, you will have to set an absolute path below
		// Note: The CAVE2 Audio Server assumes sound are in '/Users/demo/sounds/'
		// and will append that file path to any additional paths
		env->setAssetDirectory("myApp"); // Recommend using a project name
		
		// This effectively looks for '/Users/demo/sounds/myApp/beep.wav'
		sound = env->loadSoundFromFile("beep", "beep.wav");
		
		// This effectively looks for '/Users/demo/sounds/myApp/music/filmic.wav'
		music = env->loadSoundFromFile("music", "/music/bgmusic.wav");
	}
	
	~SoundTest()
	{
		// Call the SoundManager destructor, cleans up all sounds
		soundManager->~SoundManager();
	}
	
	virtual bool handleEvent(const Event& evt)
	{
		switch(evt.getServiceType())
		{
			case Service::Mocap:
				// Here we assume the mocap ID of the head tracked user is 0.
				if( evt.getSourceId() == 0 )
				{
					// evt.getPosition() returns a Vector3f
					soundManager->setListenerPosition( evt.getPosition() );
					
					// evt.getOrientation() returns a Quaternion
					soundManager->setListenerOrientation( evt.getOrientation() );
				}
		}
	}
	

Sound setup using Omegalib in C++:

	SoundEnvironment* env;
	Sound* sound;
	Sound* music;
	
	virtual void initialize()
	{
		// SoundManager initializations, listener position, and cleanup handled by engine.
		// Sound server IP and ports set by OmegaLib configuration file.
		
		env = getEngine()->getSoundEnvironment();

		// If this is not set, you will have to set an absolute path below
		// Note: The CAVE2 Audio Server assumes sound are in '/Users/demo/sounds/'
		// and will append that file path to any additional paths
		env->setAssetDirectory("myApp");
		
		// All sound files should be in .wav format
		// For positional sounds, file should be mono.
		// Rest of important sound code is in handleEvent()

		// This effectively looks for '/Users/demo/sounds/myApp/beep.wav'
		sound = env->loadSoundFromFile("beep", "beep.wav");

		music = env->loadSoundFromFile("music", "/music/bgmusic.wav");

		// Omegalib has a set of default menu sounds which play on menu opening, closing, selecting, and scrolling.
		// These can be replace with custom sounds by using a specific name for the first parameter in loadSoundFromFile():
		env->loadSoundFromFile("showMenuSound", "/my_menu/show.wav");
		env->loadSoundFromFile("hideMenuSound", "/my_menu/hide.wav");
		env->loadSoundFromFile("selectMenuSound", "/my_menu/select.wav");
		env->loadSoundFromFile("scrollMenuSound", "/my_menu/scroll.wav");

		// These can also be changed for all Omegalib applications in the configuration file.
	}

Sound setup using Omegalib in Python:

	env = getSoundEnvironment()

	# If this is not set, you will have to set an absolute path below
	# Note: The CAVE2 Audio Server assumes sound are in '/Users/demo/sounds/'
	# and will append that file path to any additional paths
	env.setAssetDirectory("myApp");

	# Using s_ to denote a sound object verses a sound instance (si_)
	# This effectively looks for '/Users/demo/sounds/myApp/beep.wav'
	s_sound = env.loadSoundFromFile("beep", "beep.wav");

	# This effectively looks for '/Users/demo/sounds/myApp/music/bgmusic.wav'
	s_music = env.loadSoundFromFile("music", "/music/bgmusic.wav");

	# Custom Omegalib menu sounds
	env.loadSoundFromFile("showMenuSound", "/my_menu/show.wav");
	env.loadSoundFromFile("hideMenuSound", "/my_menu/hide.wav");
	env.loadSoundFromFile("selectMenuSound", "/my_menu/select.wav");
	env.loadSoundFromFile("scrollMenuSound", "/my_menu/scroll.wav");

class SoundInstance

A sound instance object storing the associated sound object, instanceID, and sound parameters (volume, mix, reverb, etc.). These correspond to Supercollider nodes.

play() is used for mono .wav files that is localized in the virtual space. playStereo() is intended for stereo .wav files that will be played on four speakers in the front of CAVE2 (2-channel left/right setup).

Methods

Method(s) Description Associated OSC Messages
Playback
play() Plays a sound with the default sound parameters. /play (instanceID, bufferID, volume, xPos, yPos, zPos, listenerX, listenerY, listenerZ, width, mix, reverb, loop, pitch, playToTrigger, playToPositionTrigger, framePosition)
playStereo() Plays a stereo sound with the default sound parameters. /playStereo (instanceID, bufferID, volume, loop, pitch, playToTrigger, playToPositionTrigger, framePosition)
play(pos,volume,width,wetness,roomSize,loop) Plays a sound with the specified sound parameters. Position is in navigated/world space (meters, Y up). /play (instanceID, bufferID, volume, xPos, yPos, zPos, listenerX, listenerY, listenerZ, width, mix, reverb, loop, pitch, playToTrigger, playToPositionTrigger, framePosition)
playStereo(volume,loop) Plays a stereo sound with the specified sound parameters. /play (instanceID, bufferID, volume, loop, pitch, playToTrigger, playToPositionTrigger, framePosition)
stop() Stops the sound from playing. /freeNode (instanceID)
fade(targetVolume, duration) Fades the sound instance from it's current volume to the target volume over the specified duration in seconds /setVolEnv (instanceID, targetVolume, envelopeDuration) /setSterVolEnv(instanceID, targetVolume, envelopeDuration)
Parameters
getLoop() setLoop(loop) Gets and sets the looping flag.
getPosition(), setPosition(pos) Gets and sets the position of the sound in navigated/world space (meters, Y up). This function will convert world position to local tracker/speaker position based on the SoundEnvironment's listenerPosition. /setObjectLoc (instanceID, xPos, yPos, zPos)
getLocalPosition(), setLocalPosition(pos) Gets and sets the position of the sound in local tracker/speaker space (meters, Y up). /setObjectLoc (instanceID, xPos, yPos, zPos)
getVolume(), setVolume(volume) Gets and sets the normalized (0.0-1.0) sound instance volume. /setVol (instanceID, volume)
getWidth(), setWidth(width) Gets and sets the number of speakers (1-20) to pan the sound.
isEnvironmentSound(), setEnvironmentSound(bool) Gets and sets the environment flag (play on all 20 speakers) of the sound.
getWetness(), setWetness(wetness) Gets and sets the wetness/dryness (0.0-1.0) of the sound instance. /setReverb (nodeID, wetness, roomSize)
getRoomSize(), setRoomSize(roomSize) Gets and sets the reverb/room size (0.0-1.0) of the sound instance. /setReverb (nodeID, wetness, roomSize)
getPitch(), setPitch(pitch) Gets and sets the pitch of the sound instance (1.0 normal, 2.0 one octave up, 0.5 one octave down, -1 backwards). /setMonoRate(nodeID, pitch) /setStereoRate(nodeID, pitch)
setCurrentFrame(frameNo) Sets the current frame position of the sound instance. /setMonoFrame(nodeID, pitch) /setStereoFrame(nodeID, pitch)
isPlaying() Return true if the sound server reports the instance is currently playing
isDone() Return true if the sound server reports the instance is done playing

C++ Example:

	virtual void initialize()
	{
		// Previous SoundManager/SoundEnvironment/Sound setup
		// ....
		
		// Play some background music at startup
		// playStereo() is for ambient music and plays in a fixed left/right channel configuration
		SoundInstance* musicInst = new SoundInstance(music);
		musicInst->setVolume(0.2);
		musicInst->setLoop(true);
		musicInst->playStereo();
	}
	
	virtual bool handleEvent(const Event& evt)
	{
		if( evt.getFlags() == Event::ButtonLeft )
		{
			SoundInstance* soundInst = new SoundInstance(sound);
			
			// Place the sound at the wand position
			soundInst->setPosition( evt.getPosition() );
			
			// We could also set other sound parameters before playing
			soundInst->setVolume(0.7);
			soundInst->setRoomSize(0.5);
			
			soundInst->play();
		}
	}

Python Example:

	# Previous SoundEnvironment/Sound setup
	# ....
	
	# Play some background music at startup
	# playStereo() is for ambient music and plays in a fixed left/right channel configuration
	si_music = SoundInstance(s_music)
	
	si_music.setVolume(0.5)
	si_music.setLoop(True)
	si_music.playStereo()
	
	def onEvent():
		global playStopLight
		global moveVector
		
		e = getEvent()
		if(e.getServiceType() == ServiceType.Wand):
			
			if(e.isButtonDown( EventFlags.ButtonLeft )):
				si_sound = SoundInstance(s_sound)
				
				# Place the sound at the wand position
				si_sound.setPosition( e.getPosition() )
				
				# We could also set other sound parameters before playing
				si_sound.setVolume(0.7)
				si_sound.setRoomSize(0.5)
				
				si_sound.play()
				
	# Register our event function with Omegalib
	setEventFunction(onEvent)
Clone this wiki locally