Просмотр исходного кода

Added support for streaming Sounds

Ivan Safrin 11 лет назад
Родитель
Сommit
ed43849593

+ 35 - 2
Core/Contents/Include/PolySound.h

@@ -24,6 +24,7 @@
 #include "PolyGlobals.h"
 #include "PolyVector3.h"
 #include "PolyString.h"
+#include "PolyCoreServices.h"
 
 #if defined(__APPLE__) && defined(__MACH__)
     #include <OpenAL/al.h>
@@ -42,11 +43,31 @@
 #define ALOtherErrorStr "AL error: unknown error"
 
 #define BUFFER_SIZE 32768
+#define STREAMING_BUFFER_COUNT 2
+#define STREAMING_BUFFER_SIZE 16384
 
 namespace Polycode {
 	
 	class String;
-
+    
+    class  AudioStreamingSource {
+        public:
+            AudioStreamingSource(unsigned int channels, unsigned int bps, unsigned int freq);
+        
+            POLYIGNORE virtual unsigned int streamData(char *buffer, unsigned int size);
+        
+            unsigned int getNumChannels();
+            unsigned int getBitsPerSample();
+            unsigned int getFrequency();
+        
+        protected:
+        
+            unsigned int channels;
+            unsigned int bps;
+            unsigned int freq;
+        
+    };
+    
 	/**
 	* Loads and plays a sound. This class can load and play an OGG or WAV sound file.
 	*/
@@ -59,6 +80,8 @@ namespace Polycode {
 		*/ 
 		Sound(const String& fileName, bool generateFloatBuffer = false);
 		Sound(int size, const char *data, int channels = 1, ALsizei freq = 44100, int bps = 16, bool generateFloatBuffer = false);
+        Sound(AudioStreamingSource *streamingSource);
+        
 		virtual ~Sound();
 		
 		void loadFile(String fileName, bool generateFloatBuffer);
@@ -150,13 +173,20 @@ namespace Polycode {
 		static unsigned long readByte32(const unsigned char buffer[4]);		
 		static unsigned short readByte16(const unsigned char buffer[2]);
 		
+        void updateStream();
+        
 		POLYIGNORE std::vector<float> *getFloatBuffer();
 
 	protected:
+        
+        bool updateALBuffer(ALuint buffer);
 	
 		Number referenceDistance;
 		Number maxDistance;
-			
+        
+        bool streamingSound;
+        AudioStreamingSource *streamingSource;
+        
 		Number pitch;
 		Number volume;
 	
@@ -168,6 +198,9 @@ namespace Polycode {
 		ALuint buffer; // Kept around only for deletion purposes
 		ALuint soundSource;
 		int sampleLength;
+        
+        ALuint streamingSources;
+        ALuint streamingBuffers[STREAMING_BUFFER_COUNT];
 		
 		std::vector<float> floatBuffer;
 	};

+ 5 - 1
Core/Contents/Include/PolySoundManager.h

@@ -38,6 +38,7 @@ namespace Polycode {
 	/**
 	* Controls global sound settings.
 	*/
+    
 	class _PolyExport SoundManager : public PolyBase{
 	public:
 		SoundManager();
@@ -56,10 +57,13 @@ namespace Polycode {
 		* Sets the global sound volume.
 		*/ 
 		void setGlobalVolume(Number globalVolume);
-		
+        
+        void registerStreamingSound(Sound *sound);
+        void unregisterStreamingSound(Sound *sound);
 		
 	protected:
 		
+        std::vector<Sound*> streamingSounds;
 		ALCdevice* device;
         ALCdevice* captureDevice;
         ALbyte *recordingBuffer;

+ 94 - 2
Core/Contents/Source/PolySound.cpp

@@ -26,6 +26,7 @@
 #undef OV_EXCLUDE_STATIC_CALLBACKS
 #include "PolyString.h"
 #include "PolyLogger.h"
+#include "PolySoundManager.h"
 
 #include "OSBasics.h"
 #include <string>
@@ -39,6 +40,26 @@
 using namespace std;
 using namespace Polycode;
 
+AudioStreamingSource::AudioStreamingSource(unsigned int channels, unsigned int bps, unsigned int freq) : channels(channels), freq(freq), bps(bps) {
+}
+
+unsigned int AudioStreamingSource::getNumChannels() {
+    return channels;
+}
+
+unsigned int AudioStreamingSource::getBitsPerSample() {
+    return bps;
+}
+
+unsigned int AudioStreamingSource::getFrequency() {
+    return freq;
+}
+
+unsigned int AudioStreamingSource::streamData(char *buffer, unsigned int size) {
+    return 0;
+}
+
+
 size_t custom_readfunc(void *ptr, size_t size, size_t nmemb, void *datasource) {
 	OSFILE *file = (OSFILE*) datasource;
 	return OSBasics::read(ptr, size, nmemb, file);
@@ -59,7 +80,7 @@ long custom_tellfunc(void *datasource) {
 	return OSBasics::tell(file);
 }
 
-Sound::Sound(const String& fileName, bool generateFloatBuffer) :  referenceDistance(1), maxDistance(MAX_FLOAT), pitch(1), volume(1), sampleLength(-1) {
+Sound::Sound(const String& fileName, bool generateFloatBuffer) :  referenceDistance(1), maxDistance(MAX_FLOAT), pitch(1), volume(1), sampleLength(-1), streamingSound(false) {
 	checkALError("Construct: Loose error before construction");
 	soundLoaded = false;	
 
@@ -70,7 +91,7 @@ Sound::Sound(const String& fileName, bool generateFloatBuffer) :  referenceDista
 	checkALError("Construct from file: Finished");
 }
 
-Sound::Sound(int size, const char *data, int channels, int freq, int bps, bool generateFloatBuffer) : referenceDistance(1), maxDistance(MAX_FLOAT), pitch(1), volume(1), buffer(AL_NONE), soundSource(AL_NONE), sampleLength(-1) {
+Sound::Sound(int size, const char *data, int channels, int freq, int bps, bool generateFloatBuffer) : referenceDistance(1), maxDistance(MAX_FLOAT), pitch(1), volume(1), buffer(AL_NONE), soundSource(AL_NONE), sampleLength(-1), streamingSound(false) {
 	checkALError("Construct: Loose error before construction");
 	buffer = loadBytes(data, size, freq, channels, bps, generateFloatBuffer);
 	
@@ -84,6 +105,70 @@ Sound::Sound(int size, const char *data, int channels, int freq, int bps, bool g
 	checkALError("Construct from data: Finished");
 }
 
+Sound::Sound(AudioStreamingSource *streamingSource) : referenceDistance(1), maxDistance(MAX_FLOAT), pitch(1), volume(1), buffer(AL_NONE), soundSource(AL_NONE), sampleLength(-1), streamingSound(true), streamingSource(streamingSource) {
+    
+    
+    alGenSources(1, &soundSource);
+    
+    alSourcef(soundSource, AL_PITCH, 1.0);
+    alSourcef(soundSource, AL_GAIN, 1.0);
+    
+    ALfloat sourcePos[] = {0.0, 0.0, 0.0};
+    ALfloat sourceVel[] = {0.0, 0.0, 0.0};
+    
+    alSourcefv(soundSource, AL_POSITION, sourcePos);
+    alSourcefv(soundSource, AL_VELOCITY, sourceVel);
+    
+    
+    alGenBuffers(STREAMING_BUFFER_COUNT, streamingBuffers);
+    
+    for(int i=0; i < STREAMING_BUFFER_COUNT; i++) {
+        if(updateALBuffer(streamingBuffers[i])) {
+            alSourceQueueBuffers(soundSource, 1, &streamingBuffers[i]);
+        }
+    }
+    Services()->getSoundManager()->registerStreamingSound(this);
+    
+	alSourcePlay(soundSource);
+    
+}
+
+void Sound::updateStream() {
+    ALint processed = 0;
+    alGetSourcei(soundSource, AL_BUFFERS_PROCESSED, &processed);
+    
+    while(processed--) {
+        ALuint buffer;
+        alSourceUnqueueBuffers(soundSource, 1, &buffer);
+        if(updateALBuffer(buffer)) {
+            alSourceQueueBuffers(soundSource, 1, &buffer);
+        }
+    }
+    
+}
+
+bool Sound::updateALBuffer(ALuint buffer) {
+    
+    char data[STREAMING_BUFFER_SIZE];
+    unsigned int bytesStreamed = streamingSource->streamData(data, STREAMING_BUFFER_SIZE);
+    
+    if(bytesStreamed == 0) {
+        return false;
+    }
+    
+    ALenum format;
+    if (streamingSource->getNumChannels() == 1) {
+        format = (streamingSource->getBitsPerSample() == 8) ? AL_FORMAT_MONO8 : AL_FORMAT_MONO16;
+    } else {
+        format = (streamingSource->getBitsPerSample() == 8) ? AL_FORMAT_STEREO8 : AL_FORMAT_STEREO16;
+    }
+    
+    alBufferData(buffer, format, data, bytesStreamed, streamingSource->getFrequency());
+    
+    return true;
+}
+
+
 void Sound::loadFile(String fileName, bool generateFloatBuffer) {
 
 	if(soundLoaded) {
@@ -145,10 +230,17 @@ Number Sound::getPitch() {
 }
 
 Sound::~Sound() {
+    
+	alSourcei(soundSource, AL_BUFFER, 0);
+    
 	alDeleteSources(1,&soundSource);
 	checkALError("Destroying sound");
 	alDeleteBuffers(1, &buffer);
 	checkALError("Deleting buffer");
+    if(streamingSound) {
+        alDeleteBuffers(STREAMING_BUFFER_COUNT, streamingBuffers);
+        Services()->getSoundManager()->unregisterStreamingSound(this);
+    }
 }
 
 void Sound::soundCheck(bool result, const String& err) {

+ 17 - 0
Core/Contents/Source/PolySoundManager.cpp

@@ -137,6 +137,19 @@ Sound *SoundManager::stopRecording(bool generateFloatBuffer) {
     return newSound;
 }
 
+void SoundManager::registerStreamingSound(Sound *sound) {
+    streamingSounds.push_back(sound);
+}
+
+void SoundManager::unregisterStreamingSound(Sound *sound) {
+    for(int i=0; i < streamingSounds.size(); i++) {
+        if(streamingSounds[i] == sound) {
+            streamingSounds.erase(streamingSounds.begin()+i);
+            return;
+        }
+    }
+}
+
 void SoundManager::Update() {
     // if recording sound, save samples
     if(captureDevice) {
@@ -150,6 +163,10 @@ void SoundManager::Update() {
             recordingBufferSize += newBufferSize;
         }
     }
+    
+    for(int i=0; i < streamingSounds.size(); i++) {
+        streamingSounds[i]->updateStream();
+    }
 }
 
 SoundManager::~SoundManager() {