From 03715468ca8dedb224c9ed959db500d8bcd8d513 Mon Sep 17 00:00:00 2001 From: Josh Yelon Date: Mon, 31 Mar 2008 05:51:11 +0000 Subject: [PATCH] Improvements to audio and creation of UserDataAudio --- panda/src/audio/audioManager.h | 12 +- panda/src/audio/config_audio.cxx | 8 ++ panda/src/audio/config_audio.h | 9 +- panda/src/audio/nullAudioManager.cxx | 12 +- panda/src/audio/nullAudioManager.h | 3 +- panda/src/audiotraits/fmodAudioManager.cxx | 14 +- panda/src/audiotraits/fmodAudioManager.h | 3 +- panda/src/audiotraits/milesAudioManager.cxx | 13 +- panda/src/audiotraits/milesAudioManager.h | 3 +- panda/src/audiotraits/openalAudioManager.cxx | 30 +++- panda/src/audiotraits/openalAudioManager.h | 5 +- panda/src/audiotraits/openalAudioSound.cxx | 35 +++-- panda/src/audiotraits/openalAudioSound.h | 3 +- panda/src/movies/config_movies.cxx | 2 + panda/src/movies/movieAudioCursor.I | 63 +++++--- panda/src/movies/movieAudioCursor.cxx | 1 + panda/src/movies/movieAudioCursor.h | 2 + panda/src/movies/movies_composite1.cxx | 3 + panda/src/movies/userDataAudio.I | 18 +++ panda/src/movies/userDataAudio.cxx | 144 +++++++++++++++++++ panda/src/movies/userDataAudio.h | 72 ++++++++++ panda/src/movies/userDataAudioCursor.I | 18 +++ panda/src/movies/userDataAudioCursor.cxx | 63 ++++++++ panda/src/movies/userDataAudioCursor.h | 64 +++++++++ 24 files changed, 543 insertions(+), 57 deletions(-) create mode 100644 panda/src/movies/userDataAudio.I create mode 100644 panda/src/movies/userDataAudio.cxx create mode 100644 panda/src/movies/userDataAudio.h create mode 100644 panda/src/movies/userDataAudioCursor.I create mode 100644 panda/src/movies/userDataAudioCursor.cxx create mode 100644 panda/src/movies/userDataAudioCursor.h diff --git a/panda/src/audio/audioManager.h b/panda/src/audio/audioManager.h index 483d63e7ee..20c6dfdc4a 100644 --- a/panda/src/audio/audioManager.h +++ b/panda/src/audio/audioManager.h @@ -23,6 +23,7 @@ #include "config_audio.h" #include "audioSound.h" #include "filterProperties.h" +#include "movieAudio.h" typedef PT(AudioManager) Create_AudioManager_proc(); @@ -58,6 +59,12 @@ PUBLISHED: SPK_sideright, SPK_COUNT, }; + + enum StreamMode { + SM_heuristic, + SM_sample, + SM_stream, + }; virtual int getSpeakerSetup(); virtual void setSpeakerSetup(SpeakerModeCategory cat); @@ -86,8 +93,9 @@ PUBLISHED: virtual bool is_valid() = 0; // Get a sound: - virtual PT(AudioSound) get_sound(const string& file_name, bool positional = false) = 0; - + virtual PT(AudioSound) get_sound(const string& file_name, bool positional = false, int mode=SM_heuristic) = 0; + virtual PT(AudioSound) get_sound(MovieAudio *source, bool positional = false, int mode=SM_heuristic) = 0; + PT(AudioSound) get_null_sound(); // Tell the AudioManager there is no need to keep this one cached. diff --git a/panda/src/audio/config_audio.cxx b/panda/src/audio/config_audio.cxx index 258f4f6baf..909dcfdaad 100644 --- a/panda/src/audio/config_audio.cxx +++ b/panda/src/audio/config_audio.cxx @@ -75,6 +75,14 @@ ConfigVariableDouble audio_buffering_seconds "correctness over efficiency, but for a commercial application " "you may wish to lower this.")); +ConfigVariableInt audio_preload_threshold +("audio-preload-threshold", 1000000, + PRC_DESC("If the decompressed size of a sound file exceeds this amount, " + "then Panda3D will not attempt to store that sound file in RAM. " + "Instead, it will stream the sound file from disk. It is not " + "practical to stream multiple sound-files from disk at the same " + "time - the hard drive seek time makes it stutter.")); + // Unknown ConfigVariableInt audio_min_hw_channels diff --git a/panda/src/audio/config_audio.h b/panda/src/audio/config_audio.h index ab2df0292e..1fa330c7e1 100644 --- a/panda/src/audio/config_audio.h +++ b/panda/src/audio/config_audio.h @@ -48,10 +48,11 @@ extern EXPCL_PANDA_AUDIO ConfigVariableBool fmod_use_surround_sound; // Config vars for OpenAL: -extern EXPCL_PANDA ConfigVariableDouble audio_doppler_factor; -extern EXPCL_PANDA ConfigVariableDouble audio_distance_factor; -extern EXPCL_PANDA ConfigVariableDouble audio_drop_off_factor; -extern EXPCL_PANDA ConfigVariableDouble audio_buffering_seconds; +extern EXPCL_PANDA_AUDIO ConfigVariableDouble audio_doppler_factor; +extern EXPCL_PANDA_AUDIO ConfigVariableDouble audio_distance_factor; +extern EXPCL_PANDA_AUDIO ConfigVariableDouble audio_drop_off_factor; +extern EXPCL_PANDA_AUDIO ConfigVariableDouble audio_buffering_seconds; +extern EXPCL_PANDA_AUDIO ConfigVariableInt audio_preload_threshold; // Config vars for Miles: diff --git a/panda/src/audio/nullAudioManager.cxx b/panda/src/audio/nullAudioManager.cxx index 7e7505d3c4..9e84830902 100644 --- a/panda/src/audio/nullAudioManager.cxx +++ b/panda/src/audio/nullAudioManager.cxx @@ -63,7 +63,17 @@ is_valid() { // Description: //////////////////////////////////////////////////////////////////// PT(AudioSound) NullAudioManager:: -get_sound(const string&, bool positional) { +get_sound(const string&, bool positional, int mode) { + return get_null_sound(); +} + +//////////////////////////////////////////////////////////////////// +// Function: NullAudioManager::get_sound +// Access: Public +// Description: +//////////////////////////////////////////////////////////////////// +PT(AudioSound) NullAudioManager:: +get_sound(MovieAudio *sound, bool positional, int mode) { return get_null_sound(); } diff --git a/panda/src/audio/nullAudioManager.h b/panda/src/audio/nullAudioManager.h index e35fe86eac..c0f9242bc3 100644 --- a/panda/src/audio/nullAudioManager.h +++ b/panda/src/audio/nullAudioManager.h @@ -34,7 +34,8 @@ public: virtual bool is_valid(); - virtual PT(AudioSound) get_sound(const string&, bool positional = false); + virtual PT(AudioSound) get_sound(const string&, bool positional = false, int mode=SM_heuristic); + virtual PT(AudioSound) get_sound(MovieAudio *sound, bool positional = false, int mode=SM_heuristic); virtual void uncache_sound(const string&); virtual void clear_cache(); virtual void set_cache_limit(unsigned int); diff --git a/panda/src/audiotraits/fmodAudioManager.cxx b/panda/src/audiotraits/fmodAudioManager.cxx index 1764e7fbae..3053eec588 100644 --- a/panda/src/audiotraits/fmodAudioManager.cxx +++ b/panda/src/audiotraits/fmodAudioManager.cxx @@ -402,12 +402,12 @@ configure_filters(FilterProperties *config) { } //////////////////////////////////////////////////////////////////// -// Function: FmodAudioManager::get_sound() +// Function: FmodAudioManager::get_sound // Access: Public // Description: This is what creates a sound instance. //////////////////////////////////////////////////////////////////// PT(AudioSound) FmodAudioManager:: -get_sound(const string &file_name, bool positional) { +get_sound(const string &file_name, bool positional, int) { //Needed so People use Panda's Generic UNIX Style Paths for Filename. //path.to_os_specific() converts it back to the proper OS version later on. @@ -428,6 +428,16 @@ get_sound(const string &file_name, bool positional) { return audioSound; } +//////////////////////////////////////////////////////////////////// +// Function: FmodAudioManager::get_sound +// Access: Public +// Description: This is what creates a sound instance. +//////////////////////////////////////////////////////////////////// +PT(AudioSound) FmodAudioManager:: +get_sound(MovieAudio *source, bool positional, int) { + nassert_raise("FMOD audio manager does not support MovieAudio sources"); + return NULL; +} //////////////////////////////////////////////////////////////////// // Function: FmodAudioManager::getSpeakerSetup() diff --git a/panda/src/audiotraits/fmodAudioManager.h b/panda/src/audiotraits/fmodAudioManager.h index 3f14e2f9a8..fb996ad9c4 100644 --- a/panda/src/audiotraits/fmodAudioManager.h +++ b/panda/src/audiotraits/fmodAudioManager.h @@ -103,7 +103,8 @@ class EXPCL_FMOD_AUDIO FmodAudioManager : public AudioManager { virtual bool is_valid(); - virtual PT(AudioSound) get_sound(const string&, bool positional = false); + virtual PT(AudioSound) get_sound(const string&, bool positional = false, int mode=SM_heuristic); + virtual PT(AudioSound) get_sound(MovieAudio *, bool positional = false, int mode=SM_heuristic); virtual int getSpeakerSetup(); virtual void setSpeakerSetup(SpeakerModeCategory cat); diff --git a/panda/src/audiotraits/milesAudioManager.cxx b/panda/src/audiotraits/milesAudioManager.cxx index 4ed6eeeee8..e077e7b38c 100644 --- a/panda/src/audiotraits/milesAudioManager.cxx +++ b/panda/src/audiotraits/milesAudioManager.cxx @@ -139,7 +139,7 @@ is_valid() { // Description: //////////////////////////////////////////////////////////////////// PT(AudioSound) MilesAudioManager:: -get_sound(const string &file_name, bool) { +get_sound(const string &file_name, bool, int) { ReMutexHolder holder(_lock); audio_debug("MilesAudioManager::get_sound(file_name=\""<get_source()->get_filename().empty()) { return false; } - if (source->length() > 60.0) { + if ((source->length() > 3600.0)||(source->ready() != 0x40000000)) { return false; } int channels = source->audio_channels(); int samples = (int)(source->length() * source->audio_rate()); int bytes = samples * channels * 2; - if (bytes > 200000) { + if (bytes > audio_preload_threshold) { return false; } return true; @@ -344,12 +344,30 @@ get_sound_data(MovieAudio *movie) { } //////////////////////////////////////////////////////////////////// -// Function: OpenALAudioManager::get_sound() +// Function: OpenALAudioManager::get_sound // Access: Public // Description: This is what creates a sound instance. //////////////////////////////////////////////////////////////////// PT(AudioSound) OpenALAudioManager:: -get_sound(const string &file_name, bool positional) { +get_sound(MovieAudio *sound, bool positional, int mode) { + if(!is_valid()) { + return get_null_sound(); + } + PT(OpenALAudioSound) oas = + new OpenALAudioSound(this, sound, positional); + + _all_sounds.insert(oas); + PT(AudioSound) res = (AudioSound*)(OpenALAudioSound*)oas; + return res; +} + +//////////////////////////////////////////////////////////////////// +// Function: OpenALAudioManager::get_sound +// Access: Public +// Description: This is what creates a sound instance. +//////////////////////////////////////////////////////////////////// +PT(AudioSound) OpenALAudioManager:: +get_sound(const string &file_name, bool positional, int mode) { if(!is_valid()) { return get_null_sound(); } @@ -363,7 +381,7 @@ get_sound(const string &file_name, bool positional) { audio_error("get_sound - invalid filename"); return NULL; } - + PT(MovieAudio) mva = MovieAudio::get(path); PT(OpenALAudioSound) oas = @@ -844,7 +862,7 @@ update() { sound->push_fresh_buffers(); sound->restart_stalled_audio(); sound->cache_time(rtc); - if (sound->status()!=AudioSound::PLAYING) { + if ((sound->_source == 0)||(sound->_loops_completed >= sound->_playing_loops)) { sounds_finished.insert(*i); } } diff --git a/panda/src/audiotraits/openalAudioManager.h b/panda/src/audiotraits/openalAudioManager.h index 18b3f81444..af28a14464 100644 --- a/panda/src/audiotraits/openalAudioManager.h +++ b/panda/src/audiotraits/openalAudioManager.h @@ -53,7 +53,8 @@ class EXPCL_OPENAL_AUDIO OpenALAudioManager : public AudioManager { virtual bool is_valid(); - virtual PT(AudioSound) get_sound(const string&, bool positional = false); + virtual PT(AudioSound) get_sound(const string&, bool positional = false, int mode=SM_heuristic); + virtual PT(AudioSound) get_sound(MovieAudio *sound, bool positional = false, int mode=SM_heuristic); virtual void uncache_sound(const string&); virtual void clear_cache(); @@ -173,7 +174,7 @@ private: typedef phash_map SampleCache; SampleCache _sample_cache; - typedef phash_set SoundsPlaying; + typedef phash_set SoundsPlaying; SoundsPlaying _sounds_playing; typedef phash_set AllSounds; diff --git a/panda/src/audiotraits/openalAudioSound.cxx b/panda/src/audiotraits/openalAudioSound.cxx index b947ba0678..aff8b49d5b 100644 --- a/panda/src/audiotraits/openalAudioSound.cxx +++ b/panda/src/audiotraits/openalAudioSound.cxx @@ -316,7 +316,7 @@ restart_stalled_audio() { // Description: Pushes a buffer into the source queue. //////////////////////////////////////////////////////////////////// void OpenALAudioSound:: -queue_buffer(ALuint buffer, int loop_index, double time_offset) { +queue_buffer(ALuint buffer, int samples, int loop_index, double time_offset) { // Now push the buffer into the stream queue. alGetError(); alSourceQueueBuffers(_source,1,&buffer); @@ -328,10 +328,10 @@ queue_buffer(ALuint buffer, int loop_index, double time_offset) { } QueuedBuffer buf; buf._buffer = buffer; + buf._samples = samples; buf._loop_index = loop_index; buf._time_offset = time_offset; _stream_queued.push_back(buf); - // audio_debug("Buffer queued " << loop_index << " " << time_offset); } //////////////////////////////////////////////////////////////////// @@ -394,9 +394,18 @@ read_stream_data(int bytelen, unsigned char *buffer) { cursor->seek(0.0); continue; } + if (_sd->_stream->ready() == 0) { + if (_sd->_stream->aborted()) { + _loops_completed = _playing_loops; + } + return fill; + } if (samples > space) { samples = space; } + if (samples > _sd->_stream->ready()) { + samples = _sd->_stream->ready(); + } cursor->read_samples(samples, (PN_int16 *)buffer); size_t hval = AddHash::add_hash(0, (PN_uint8*)buffer, samples*channels*2); audio_debug("Streaming " << cursor->get_source()->get_filename().get_basename() << " at " << t << " hash " << hval); @@ -490,23 +499,21 @@ push_fresh_buffers() { if (_sd->_sample) { while ((_loops_completed < _playing_loops) && (_stream_queued.size() < 100)) { - queue_buffer(_sd->_sample, _loops_completed, 0.0); + queue_buffer(_sd->_sample, 0,_loops_completed, 0.0); _loops_completed += 1; } } else { MovieAudioCursor *cursor = _sd->_stream; int channels = cursor->audio_channels(); int rate = cursor->audio_rate(); - double space = 65536 / (channels * 2); - // Calculate how many buffers to keep in the queue. - int fill_to = (int)((audio_buffering_seconds * rate) / space) + 1; - if (fill_to < 3) { - fill_to = 3; + int fill = 0; + for (int i=0; i<_stream_queued.size(); i++) { + fill += _stream_queued[i]._samples; } while ((_loops_completed < _playing_loops) && - (((int)(_stream_queued.size())) < fill_to)) { + (fill < (int)(audio_buffering_seconds * rate * channels))) { int loop_index = _loops_completed; double time_offset = cursor->tell(); int samples = read_stream_data(65536, data); @@ -515,8 +522,9 @@ push_fresh_buffers() { } ALuint buffer = make_buffer(samples, channels, rate, data); if (_manager == 0) return; - queue_buffer(buffer, loop_index, time_offset); + queue_buffer(buffer, samples, loop_index, time_offset); if (_manager == 0) return; + fill += samples; } } } @@ -866,17 +874,14 @@ get_name() const { // Description: Get status of the sound. // // This returns the status as of the -// last AudioManager::update. +// last push_fresh_buffers //////////////////////////////////////////////////////////////////// AudioSound::SoundStatus OpenALAudioSound:: status() const { if (_source==0) { return AudioSound::READY; } - - _manager->make_current(); - - if (_stream_queued.size() == 0) { + if (_loops_completed >= _playing_loops) { return AudioSound::READY; } else { return AudioSound::PLAYING; diff --git a/panda/src/audiotraits/openalAudioSound.h b/panda/src/audiotraits/openalAudioSound.h index a019a92a84..eb180e193c 100644 --- a/panda/src/audiotraits/openalAudioSound.h +++ b/panda/src/audiotraits/openalAudioSound.h @@ -125,7 +125,7 @@ private: void restart_stalled_audio(); void delete_queued_buffers(); ALuint make_buffer(int samples, int channels, int rate, unsigned char *data); - void queue_buffer(ALuint buffer, int loop_index, double time_offset); + void queue_buffer(ALuint buffer, int samples, int loop_index, double time_offset); int read_stream_data(int bytelen, unsigned char *data); void pull_used_buffers(); void push_fresh_buffers(); @@ -139,6 +139,7 @@ private: struct QueuedBuffer { ALuint _buffer; + int _samples; int _loop_index; double _time_offset; }; diff --git a/panda/src/movies/config_movies.cxx b/panda/src/movies/config_movies.cxx index d38dcbb9ad..efd362f7cf 100644 --- a/panda/src/movies/config_movies.cxx +++ b/panda/src/movies/config_movies.cxx @@ -53,6 +53,8 @@ init_libmovies() { MovieAudioCursor::init_type(); InkblotVideo::init_type(); InkblotVideoCursor::init_type(); + UserDataAudio::init_type(); + UserDataAudioCursor::init_type(); WebcamVideo::init_type(); #ifdef HAVE_FFMPEG FfmpegVideo::init_type(); diff --git a/panda/src/movies/movieAudioCursor.I b/panda/src/movies/movieAudioCursor.I index 2c77f85884..196e0837d1 100644 --- a/panda/src/movies/movieAudioCursor.I +++ b/panda/src/movies/movieAudioCursor.I @@ -50,39 +50,64 @@ audio_channels() const { //////////////////////////////////////////////////////////////////// // Function: MovieAudioCursor::length // Access: Public -// Description: Returns the length of the movie. +// Description: Returns the length of the movie. Attempting to read +// audio samples beyond the specified length will produce +// silent samples. // // Some kinds of Movie, such as internet TV station, // might not have a predictable length. In that case, // the length will be set to a very large number: 1.0E10. -// If the internet TV station goes offline, the video -// or audio stream will set its abort flag. Reaching the -// end of the movie (ie, the specified length) normally -// does not cause the abort flag to be set. -// -// The video and audio streams produced by get_video and -// get_audio are always of unlimited duration - you can -// always read another video frame or another audio -// sample. This is true even if the specified length -// is reached, or an abort is flagged. If either stream -// runs out of data, it will synthesize blank video -// frames and silent audio samples as necessary to -// satisfy read requests. // // Some AVI files have incorrect length values encoded -// into them - usually, they're a second or two long or +// into them - they may be a second or two long or // short. When playing such an AVI using the Movie class, // you may see a slightly truncated video, or a slightly // elongated video (padded with black frames). There are // utilities out there to fix the length values in AVI // files. // +// An audio consumer needs to check the length, the +// ready status, and the aborted flag. //////////////////////////////////////////////////////////////////// INLINE double MovieAudioCursor:: length() const { return _length; } +//////////////////////////////////////////////////////////////////// +// Function: MovieAudioCursor::ready +// Access: Public +// Description: Returns the number of audio samples that are ready +// to read. This is primarily relevant for sources like +// microphones which produce samples at a fixed rate. +// If you try to read more samples than are ready, the +// result will be silent samples. +// +// Some audio streams do not have a limit on how fast +// they can produce samples. Such streams will always +// return 0x40000000 as the ready-count. This may well +// exceed the length of the audio stream. You therefore +// need to check length separately. +// +// If the aborted flag is set, that means the ready count +// is no longer being replenished. For example, a +// MovieAudioCursor might be reading from an internet +// radio station, and it might buffer data to avoid +// underruns. If it loses connection to the radio +// station, it will set the aborted flag to indicate that +// the buffer is no longer being replenished. But it is +// still ok to read the samples that are in the buffer, +// at least until they run out. Once those are gone, +// there will be no more. +// +// An audio consumer needs to check the length, the +// ready status, and the aborted flag. +//////////////////////////////////////////////////////////////////// +INLINE int MovieAudioCursor:: +ready() const { + return _ready; +} + //////////////////////////////////////////////////////////////////// // Function: MovieAudioCursor::can_seek // Access: Public @@ -113,11 +138,9 @@ can_seek_fast() const { //////////////////////////////////////////////////////////////////// // Function: MovieAudioCursor::aborted // Access: Public -// Description: Returns true if the audio has aborted prematurely. -// For example, this could occur if the Movie was actually -// an internet TV station, and the connection was lost. -// Reaching the normal end of the audio does not -// constitute an 'abort' condition. +// Description: If aborted is true, it means that the "ready" samples +// are not being replenished. See the method "ready" +// for an explanation. //////////////////////////////////////////////////////////////////// INLINE bool MovieAudioCursor:: aborted() const { diff --git a/panda/src/movies/movieAudioCursor.cxx b/panda/src/movies/movieAudioCursor.cxx index 4cab95d1e8..f35d6a582c 100644 --- a/panda/src/movies/movieAudioCursor.cxx +++ b/panda/src/movies/movieAudioCursor.cxx @@ -36,6 +36,7 @@ MovieAudioCursor(MovieAudio *src) : _length(1.0E10), _can_seek(true), _can_seek_fast(true), + _ready(0x40000000), _aborted(false), _samples_read(0) { diff --git a/panda/src/movies/movieAudioCursor.h b/panda/src/movies/movieAudioCursor.h index ea9ba2c642..c1949c040a 100644 --- a/panda/src/movies/movieAudioCursor.h +++ b/panda/src/movies/movieAudioCursor.h @@ -53,6 +53,7 @@ PUBLISHED: INLINE bool aborted() const; INLINE double tell() const; INLINE void skip_samples(int n); + INLINE int ready() const; virtual void seek(double offset); public: @@ -62,6 +63,7 @@ protected: PT(MovieAudio) _source; int _audio_rate; int _audio_channels; + int _ready; double _length; bool _can_seek; bool _can_seek_fast; diff --git a/panda/src/movies/movies_composite1.cxx b/panda/src/movies/movies_composite1.cxx index 80a3cf2afa..39d57c5c94 100644 --- a/panda/src/movies/movies_composite1.cxx +++ b/panda/src/movies/movies_composite1.cxx @@ -15,6 +15,9 @@ #include "ffmpegVirtualFile.cxx" +#include "userDataAudio.cxx" +#include "userDataAudioCursor.cxx" + #include "webcamVideo.cxx" #include "webcamVideoDS.cxx" diff --git a/panda/src/movies/userDataAudio.I b/panda/src/movies/userDataAudio.I new file mode 100644 index 0000000000..a7a67d8871 --- /dev/null +++ b/panda/src/movies/userDataAudio.I @@ -0,0 +1,18 @@ +// Filename: userDataAudio.I +// Created by: jyelon (02Jul07) +// +//////////////////////////////////////////////////////////////////// +// +// PANDA 3D SOFTWARE +// Copyright (c) 2001 - 2004, Disney Enterprises, Inc. All rights reserved +// +// All use of this software is subject to the terms of the Panda 3d +// Software license. You should have received a copy of this license +// along with this source code; you will also find a current copy of +// the license at http://etc.cmu.edu/panda3d/docs/license/ . +// +// To contact the maintainers of this program write to +// panda3d-general@lists.sourceforge.net . +// +//////////////////////////////////////////////////////////////////// + diff --git a/panda/src/movies/userDataAudio.cxx b/panda/src/movies/userDataAudio.cxx new file mode 100644 index 0000000000..eb6f76eeb5 --- /dev/null +++ b/panda/src/movies/userDataAudio.cxx @@ -0,0 +1,144 @@ +// Filename: userDataAudio.cxx +// Created by: jyelon (02Jul07) +// +//////////////////////////////////////////////////////////////////// +// +// PANDA 3D SOFTWARE +// Copyright (c) 2001 - 2007, Disney Enterprises, Inc. All rights reserved +// +// All use of this software is subject to the terms of the Panda 3d +// Software license. You should have received a copy of this license +// along with this source code; you will also find a current copy of +// the license at http://etc.cmu.edu/panda3d/docs/license/ . +// +// To contact the maintainers of this program write to +// panda3d-general@lists.sourceforge.net +// +//////////////////////////////////////////////////////////////////// + +#include "userDataAudio.h" +#include "userDataAudioCursor.h" + +TypeHandle UserDataAudio::_type_handle; + +//////////////////////////////////////////////////////////////////// +// Function: UserDataAudio::Constructor +// Access: Public +// Description: This constructor returns a UserDataAudio --- +// a means to supply raw audio samples manually. +//////////////////////////////////////////////////////////////////// +UserDataAudio:: +UserDataAudio(int rate, int channels) : + MovieAudio("User Data Audio"), + _desired_rate(rate), + _desired_channels(channels), + _aborted(false), + _cursor(NULL) +{ +} + +//////////////////////////////////////////////////////////////////// +// Function: UserDataAudio::Destructor +// Access: Public, Virtual +// Description: +//////////////////////////////////////////////////////////////////// +UserDataAudio:: +~UserDataAudio() { +} + +//////////////////////////////////////////////////////////////////// +// Function: UserDataAudio::update_cursor +// Access: Private +// Description: Make sure that the UserDataAudioCursor's ready +// and aborted status flags are correct. +//////////////////////////////////////////////////////////////////// +void UserDataAudio:: +update_cursor() { + if (_cursor == 0) return; + _cursor->_ready = _data.size(); + _cursor->_aborted = _aborted; +} + +//////////////////////////////////////////////////////////////////// +// Function: UserDataAudio::open +// Access: Published, Virtual +// Description: Open this audio, returning a UserDataAudioCursor. A +// UserDataAudio can only be opened by one consumer +// at a time. +//////////////////////////////////////////////////////////////////// +PT(MovieAudioCursor) UserDataAudio:: +open() { + if (_cursor) { + nassert_raise("A UserDataAudio can only be opened by one consumer at a time."); + return NULL; + } + _cursor = new UserDataAudioCursor(this); + update_cursor(); + return _cursor; +} + +//////////////////////////////////////////////////////////////////// +// Function: UserDataAudio::read_samples +// Access: Private +// Description: Read audio samples from the stream. N is the +// number of samples you wish to read. Your buffer +// must be equal in size to N * channels. +// Multiple-channel audio will be interleaved. +//////////////////////////////////////////////////////////////////// +void UserDataAudio:: +read_samples(int n, PN_int16 *data) { + int nread = n; + if (nread > (int)_data.size()) { + nread = _data.size(); + } + for (int i=0; i _data; + bool _aborted; + friend class UserDataAudioCursor; + + public: + static TypeHandle get_class_type() { + return _type_handle; + } + static void init_type() { + MovieAudio::init_type(); + register_type(_type_handle, "UserDataAudio", + MovieAudio::get_class_type()); + } + virtual TypeHandle get_type() const { + return get_class_type(); + } + virtual TypeHandle force_init_type() {init_type(); return get_class_type();} + + private: + static TypeHandle _type_handle; +}; + +#include "userDataAudio.I" + +#endif diff --git a/panda/src/movies/userDataAudioCursor.I b/panda/src/movies/userDataAudioCursor.I new file mode 100644 index 0000000000..902c4b0a0f --- /dev/null +++ b/panda/src/movies/userDataAudioCursor.I @@ -0,0 +1,18 @@ +// Filename: userDataAudioCursor.I +// Created by: jyelon (02Jul07) +// +//////////////////////////////////////////////////////////////////// +// +// PANDA 3D SOFTWARE +// Copyright (c) 2001 - 2004, Disney Enterprises, Inc. All rights reserved +// +// All use of this software is subject to the terms of the Panda 3d +// Software license. You should have received a copy of this license +// along with this source code; you will also find a current copy of +// the license at http://etc.cmu.edu/panda3d/docs/license/ . +// +// To contact the maintainers of this program write to +// panda3d-general@lists.sourceforge.net . +// +//////////////////////////////////////////////////////////////////// + diff --git a/panda/src/movies/userDataAudioCursor.cxx b/panda/src/movies/userDataAudioCursor.cxx new file mode 100644 index 0000000000..8cea726787 --- /dev/null +++ b/panda/src/movies/userDataAudioCursor.cxx @@ -0,0 +1,63 @@ +// Filename: userDataAudioCursor.cxx +// Created by: jyelon (02Jul07) +// +//////////////////////////////////////////////////////////////////// +// +// PANDA 3D SOFTWARE +// Copyright (c) 2001 - 2007, Disney Enterprises, Inc. All rights reserved +// +// All use of this software is subject to the terms of the Panda 3d +// Software license. You should have received a copy of this license +// along with this source code; you will also find a current copy of +// the license at http://etc.cmu.edu/panda3d/docs/license/ . +// +// To contact the maintainers of this program write to +// panda3d-general@lists.sourceforge.net +// +//////////////////////////////////////////////////////////////////// + +#include "userDataAudioCursor.h" + +TypeHandle UserDataAudioCursor::_type_handle; + +//////////////////////////////////////////////////////////////////// +// Function: UserDataAudioCursor::Constructor +// Access: +// Description: +//////////////////////////////////////////////////////////////////// +UserDataAudioCursor:: +UserDataAudioCursor(UserDataAudio *src) : + MovieAudioCursor(src) +{ + _audio_rate = src->_desired_rate; + _audio_channels = src->_desired_channels; + _can_seek = false; + _can_seek_fast = false; + _ready = 0; + _aborted = false; +} + +//////////////////////////////////////////////////////////////////// +// Function: UserDataAudioCursor::Destructor +// Access: Public, Virtual +// Description: +//////////////////////////////////////////////////////////////////// +UserDataAudioCursor:: +~UserDataAudioCursor() { + UserDataAudio *source = (UserDataAudio*)(MovieAudio*)_source; + source->_cursor = NULL; +} + +//////////////////////////////////////////////////////////////////// +// Function: UserDataAudioCursor::read_samples +// Access: Private +// Description: Read audio samples from the stream. N is the +// number of samples you wish to read. Your buffer +// must be equal in size to N * channels. +// Multiple-channel audio will be interleaved. +//////////////////////////////////////////////////////////////////// +void UserDataAudioCursor:: +read_samples(int n, PN_int16 *data) { + UserDataAudio *source = (UserDataAudio*)(MovieAudio*)_source; + source->read_samples(n, data); +} diff --git a/panda/src/movies/userDataAudioCursor.h b/panda/src/movies/userDataAudioCursor.h new file mode 100644 index 0000000000..3a1ae9dcb6 --- /dev/null +++ b/panda/src/movies/userDataAudioCursor.h @@ -0,0 +1,64 @@ +// Filename: userDataAudioCursor.h +// Created by: jyelon (02Jul07) +// +//////////////////////////////////////////////////////////////////// +// +// PANDA 3D SOFTWARE +// Copyright (c) 2001 - 2004, Disney Enterprises, Inc. All rights reserved +// +// All use of this software is subject to the terms of the Panda 3d +// Software license. You should have received a copy of this license +// along with this source code; you will also find a current copy of +// the license at http://etc.cmu.edu/panda3d/docs/license/ . +// +// To contact the maintainers of this program write to +// panda3d-general@lists.sourceforge.net . +// +//////////////////////////////////////////////////////////////////// + +#ifndef USERDATAAUDIOCURSOR_H +#define USERDATAAUDIOCURSOR_H + +#include "pandabase.h" +#include "luse.h" +#include "pointerTo.h" +#include "pointerToArray.h" +class UserDataAudio; + +//////////////////////////////////////////////////////////////////// +// Class : UserDataAudioCursor +// Description : A UserDataAudioCursor is a means to manually +// supply a sequence of raw audio samples. +//////////////////////////////////////////////////////////////////// +class EXPCL_PANDA_MOVIES UserDataAudioCursor : public MovieAudioCursor { + +PUBLISHED: + UserDataAudioCursor(UserDataAudio *src); + virtual ~UserDataAudioCursor(); + +public: + virtual void read_samples(int n, PN_int16 *data); + friend class UserDataAudio; + +public: + static TypeHandle get_class_type() { + return _type_handle; + } + static void init_type() { + MovieAudioCursor::init_type(); + register_type(_type_handle, "UserDataAudioCursor", + MovieAudioCursor::get_class_type()); + } + virtual TypeHandle get_type() const { + return get_class_type(); + } + virtual TypeHandle force_init_type() {init_type(); return get_class_type();} + +private: + static TypeHandle _type_handle; +}; + +#include "userDataAudioCursor.I" +#include "userDataAudio.h" + +#endif