mirror of
https://github.com/panda3d/panda3d.git
synced 2025-10-03 02:15:43 -04:00
Improvements to audio and creation of UserDataAudio
This commit is contained in:
parent
972f0c50e7
commit
03715468ca
@ -23,6 +23,7 @@
|
|||||||
#include "config_audio.h"
|
#include "config_audio.h"
|
||||||
#include "audioSound.h"
|
#include "audioSound.h"
|
||||||
#include "filterProperties.h"
|
#include "filterProperties.h"
|
||||||
|
#include "movieAudio.h"
|
||||||
|
|
||||||
typedef PT(AudioManager) Create_AudioManager_proc();
|
typedef PT(AudioManager) Create_AudioManager_proc();
|
||||||
|
|
||||||
@ -58,6 +59,12 @@ PUBLISHED:
|
|||||||
SPK_sideright,
|
SPK_sideright,
|
||||||
SPK_COUNT,
|
SPK_COUNT,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
enum StreamMode {
|
||||||
|
SM_heuristic,
|
||||||
|
SM_sample,
|
||||||
|
SM_stream,
|
||||||
|
};
|
||||||
|
|
||||||
virtual int getSpeakerSetup();
|
virtual int getSpeakerSetup();
|
||||||
virtual void setSpeakerSetup(SpeakerModeCategory cat);
|
virtual void setSpeakerSetup(SpeakerModeCategory cat);
|
||||||
@ -86,8 +93,9 @@ PUBLISHED:
|
|||||||
virtual bool is_valid() = 0;
|
virtual bool is_valid() = 0;
|
||||||
|
|
||||||
// Get a sound:
|
// 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();
|
PT(AudioSound) get_null_sound();
|
||||||
|
|
||||||
// Tell the AudioManager there is no need to keep this one cached.
|
// Tell the AudioManager there is no need to keep this one cached.
|
||||||
|
@ -75,6 +75,14 @@ ConfigVariableDouble audio_buffering_seconds
|
|||||||
"correctness over efficiency, but for a commercial application "
|
"correctness over efficiency, but for a commercial application "
|
||||||
"you may wish to lower this."));
|
"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
|
// Unknown
|
||||||
|
|
||||||
ConfigVariableInt audio_min_hw_channels
|
ConfigVariableInt audio_min_hw_channels
|
||||||
|
@ -48,10 +48,11 @@ extern EXPCL_PANDA_AUDIO ConfigVariableBool fmod_use_surround_sound;
|
|||||||
|
|
||||||
// Config vars for OpenAL:
|
// Config vars for OpenAL:
|
||||||
|
|
||||||
extern EXPCL_PANDA ConfigVariableDouble audio_doppler_factor;
|
extern EXPCL_PANDA_AUDIO ConfigVariableDouble audio_doppler_factor;
|
||||||
extern EXPCL_PANDA ConfigVariableDouble audio_distance_factor;
|
extern EXPCL_PANDA_AUDIO ConfigVariableDouble audio_distance_factor;
|
||||||
extern EXPCL_PANDA ConfigVariableDouble audio_drop_off_factor;
|
extern EXPCL_PANDA_AUDIO ConfigVariableDouble audio_drop_off_factor;
|
||||||
extern EXPCL_PANDA ConfigVariableDouble audio_buffering_seconds;
|
extern EXPCL_PANDA_AUDIO ConfigVariableDouble audio_buffering_seconds;
|
||||||
|
extern EXPCL_PANDA_AUDIO ConfigVariableInt audio_preload_threshold;
|
||||||
|
|
||||||
// Config vars for Miles:
|
// Config vars for Miles:
|
||||||
|
|
||||||
|
@ -63,7 +63,17 @@ is_valid() {
|
|||||||
// Description:
|
// Description:
|
||||||
////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////
|
||||||
PT(AudioSound) NullAudioManager::
|
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();
|
return get_null_sound();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -34,7 +34,8 @@ public:
|
|||||||
|
|
||||||
virtual bool is_valid();
|
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 uncache_sound(const string&);
|
||||||
virtual void clear_cache();
|
virtual void clear_cache();
|
||||||
virtual void set_cache_limit(unsigned int);
|
virtual void set_cache_limit(unsigned int);
|
||||||
|
@ -402,12 +402,12 @@ configure_filters(FilterProperties *config) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////
|
||||||
// Function: FmodAudioManager::get_sound()
|
// Function: FmodAudioManager::get_sound
|
||||||
// Access: Public
|
// Access: Public
|
||||||
// Description: This is what creates a sound instance.
|
// Description: This is what creates a sound instance.
|
||||||
////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////
|
||||||
PT(AudioSound) FmodAudioManager::
|
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.
|
//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.
|
//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;
|
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()
|
// Function: FmodAudioManager::getSpeakerSetup()
|
||||||
|
@ -103,7 +103,8 @@ class EXPCL_FMOD_AUDIO FmodAudioManager : public AudioManager {
|
|||||||
|
|
||||||
virtual bool is_valid();
|
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 int getSpeakerSetup();
|
||||||
virtual void setSpeakerSetup(SpeakerModeCategory cat);
|
virtual void setSpeakerSetup(SpeakerModeCategory cat);
|
||||||
|
@ -139,7 +139,7 @@ is_valid() {
|
|||||||
// Description:
|
// Description:
|
||||||
////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////
|
||||||
PT(AudioSound) MilesAudioManager::
|
PT(AudioSound) MilesAudioManager::
|
||||||
get_sound(const string &file_name, bool) {
|
get_sound(const string &file_name, bool, int) {
|
||||||
ReMutexHolder holder(_lock);
|
ReMutexHolder holder(_lock);
|
||||||
audio_debug("MilesAudioManager::get_sound(file_name=\""<<file_name<<"\")");
|
audio_debug("MilesAudioManager::get_sound(file_name=\""<<file_name<<"\")");
|
||||||
|
|
||||||
@ -223,6 +223,17 @@ get_sound(const string &file_name, bool) {
|
|||||||
return audioSound;
|
return audioSound;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////
|
||||||
|
// Function: MilesAudioManager::get_sound
|
||||||
|
// Access: Public, Virtual
|
||||||
|
// Description:
|
||||||
|
////////////////////////////////////////////////////////////////////
|
||||||
|
PT(AudioSound) MilesAudioManager::
|
||||||
|
get_sound(MovieAudio *sound, bool, int) {
|
||||||
|
nassert_raise("Miles audio manager does not support MovieAudio sources.");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////
|
||||||
// Function: MilesAudioManager::uncache_sound
|
// Function: MilesAudioManager::uncache_sound
|
||||||
// Access: Public, Virtual
|
// Access: Public, Virtual
|
||||||
|
@ -47,7 +47,8 @@ public:
|
|||||||
|
|
||||||
virtual bool is_valid();
|
virtual bool is_valid();
|
||||||
|
|
||||||
virtual PT(AudioSound) get_sound(const string &file_name, bool positional = false);
|
virtual PT(AudioSound) get_sound(const string &file_name, 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 &file_name);
|
virtual void uncache_sound(const string &file_name);
|
||||||
virtual void clear_cache();
|
virtual void clear_cache();
|
||||||
virtual void set_cache_limit(unsigned int count);
|
virtual void set_cache_limit(unsigned int count);
|
||||||
|
@ -244,13 +244,13 @@ can_load_audio(MovieAudioCursor *source) {
|
|||||||
if (source->get_source()->get_filename().empty()) {
|
if (source->get_source()->get_filename().empty()) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (source->length() > 60.0) {
|
if ((source->length() > 3600.0)||(source->ready() != 0x40000000)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
int channels = source->audio_channels();
|
int channels = source->audio_channels();
|
||||||
int samples = (int)(source->length() * source->audio_rate());
|
int samples = (int)(source->length() * source->audio_rate());
|
||||||
int bytes = samples * channels * 2;
|
int bytes = samples * channels * 2;
|
||||||
if (bytes > 200000) {
|
if (bytes > audio_preload_threshold) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
@ -344,12 +344,30 @@ get_sound_data(MovieAudio *movie) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////
|
||||||
// Function: OpenALAudioManager::get_sound()
|
// Function: OpenALAudioManager::get_sound
|
||||||
// Access: Public
|
// Access: Public
|
||||||
// Description: This is what creates a sound instance.
|
// Description: This is what creates a sound instance.
|
||||||
////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////
|
||||||
PT(AudioSound) OpenALAudioManager::
|
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()) {
|
if(!is_valid()) {
|
||||||
return get_null_sound();
|
return get_null_sound();
|
||||||
}
|
}
|
||||||
@ -363,7 +381,7 @@ get_sound(const string &file_name, bool positional) {
|
|||||||
audio_error("get_sound - invalid filename");
|
audio_error("get_sound - invalid filename");
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
PT(MovieAudio) mva = MovieAudio::get(path);
|
PT(MovieAudio) mva = MovieAudio::get(path);
|
||||||
|
|
||||||
PT(OpenALAudioSound) oas =
|
PT(OpenALAudioSound) oas =
|
||||||
@ -844,7 +862,7 @@ update() {
|
|||||||
sound->push_fresh_buffers();
|
sound->push_fresh_buffers();
|
||||||
sound->restart_stalled_audio();
|
sound->restart_stalled_audio();
|
||||||
sound->cache_time(rtc);
|
sound->cache_time(rtc);
|
||||||
if (sound->status()!=AudioSound::PLAYING) {
|
if ((sound->_source == 0)||(sound->_loops_completed >= sound->_playing_loops)) {
|
||||||
sounds_finished.insert(*i);
|
sounds_finished.insert(*i);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -53,7 +53,8 @@ class EXPCL_OPENAL_AUDIO OpenALAudioManager : public AudioManager {
|
|||||||
|
|
||||||
virtual bool is_valid();
|
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 uncache_sound(const string&);
|
||||||
virtual void clear_cache();
|
virtual void clear_cache();
|
||||||
@ -173,7 +174,7 @@ private:
|
|||||||
typedef phash_map<string, SoundData *> SampleCache;
|
typedef phash_map<string, SoundData *> SampleCache;
|
||||||
SampleCache _sample_cache;
|
SampleCache _sample_cache;
|
||||||
|
|
||||||
typedef phash_set<OpenALAudioSound *> SoundsPlaying;
|
typedef phash_set<PT(OpenALAudioSound)> SoundsPlaying;
|
||||||
SoundsPlaying _sounds_playing;
|
SoundsPlaying _sounds_playing;
|
||||||
|
|
||||||
typedef phash_set<OpenALAudioSound *> AllSounds;
|
typedef phash_set<OpenALAudioSound *> AllSounds;
|
||||||
|
@ -316,7 +316,7 @@ restart_stalled_audio() {
|
|||||||
// Description: Pushes a buffer into the source queue.
|
// Description: Pushes a buffer into the source queue.
|
||||||
////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////
|
||||||
void OpenALAudioSound::
|
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.
|
// Now push the buffer into the stream queue.
|
||||||
alGetError();
|
alGetError();
|
||||||
alSourceQueueBuffers(_source,1,&buffer);
|
alSourceQueueBuffers(_source,1,&buffer);
|
||||||
@ -328,10 +328,10 @@ queue_buffer(ALuint buffer, int loop_index, double time_offset) {
|
|||||||
}
|
}
|
||||||
QueuedBuffer buf;
|
QueuedBuffer buf;
|
||||||
buf._buffer = buffer;
|
buf._buffer = buffer;
|
||||||
|
buf._samples = samples;
|
||||||
buf._loop_index = loop_index;
|
buf._loop_index = loop_index;
|
||||||
buf._time_offset = time_offset;
|
buf._time_offset = time_offset;
|
||||||
_stream_queued.push_back(buf);
|
_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);
|
cursor->seek(0.0);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
if (_sd->_stream->ready() == 0) {
|
||||||
|
if (_sd->_stream->aborted()) {
|
||||||
|
_loops_completed = _playing_loops;
|
||||||
|
}
|
||||||
|
return fill;
|
||||||
|
}
|
||||||
if (samples > space) {
|
if (samples > space) {
|
||||||
samples = space;
|
samples = space;
|
||||||
}
|
}
|
||||||
|
if (samples > _sd->_stream->ready()) {
|
||||||
|
samples = _sd->_stream->ready();
|
||||||
|
}
|
||||||
cursor->read_samples(samples, (PN_int16 *)buffer);
|
cursor->read_samples(samples, (PN_int16 *)buffer);
|
||||||
size_t hval = AddHash::add_hash(0, (PN_uint8*)buffer, samples*channels*2);
|
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);
|
audio_debug("Streaming " << cursor->get_source()->get_filename().get_basename() << " at " << t << " hash " << hval);
|
||||||
@ -490,23 +499,21 @@ push_fresh_buffers() {
|
|||||||
if (_sd->_sample) {
|
if (_sd->_sample) {
|
||||||
while ((_loops_completed < _playing_loops) &&
|
while ((_loops_completed < _playing_loops) &&
|
||||||
(_stream_queued.size() < 100)) {
|
(_stream_queued.size() < 100)) {
|
||||||
queue_buffer(_sd->_sample, _loops_completed, 0.0);
|
queue_buffer(_sd->_sample, 0,_loops_completed, 0.0);
|
||||||
_loops_completed += 1;
|
_loops_completed += 1;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
MovieAudioCursor *cursor = _sd->_stream;
|
MovieAudioCursor *cursor = _sd->_stream;
|
||||||
int channels = cursor->audio_channels();
|
int channels = cursor->audio_channels();
|
||||||
int rate = cursor->audio_rate();
|
int rate = cursor->audio_rate();
|
||||||
double space = 65536 / (channels * 2);
|
|
||||||
|
|
||||||
// Calculate how many buffers to keep in the queue.
|
int fill = 0;
|
||||||
int fill_to = (int)((audio_buffering_seconds * rate) / space) + 1;
|
for (int i=0; i<_stream_queued.size(); i++) {
|
||||||
if (fill_to < 3) {
|
fill += _stream_queued[i]._samples;
|
||||||
fill_to = 3;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
while ((_loops_completed < _playing_loops) &&
|
while ((_loops_completed < _playing_loops) &&
|
||||||
(((int)(_stream_queued.size())) < fill_to)) {
|
(fill < (int)(audio_buffering_seconds * rate * channels))) {
|
||||||
int loop_index = _loops_completed;
|
int loop_index = _loops_completed;
|
||||||
double time_offset = cursor->tell();
|
double time_offset = cursor->tell();
|
||||||
int samples = read_stream_data(65536, data);
|
int samples = read_stream_data(65536, data);
|
||||||
@ -515,8 +522,9 @@ push_fresh_buffers() {
|
|||||||
}
|
}
|
||||||
ALuint buffer = make_buffer(samples, channels, rate, data);
|
ALuint buffer = make_buffer(samples, channels, rate, data);
|
||||||
if (_manager == 0) return;
|
if (_manager == 0) return;
|
||||||
queue_buffer(buffer, loop_index, time_offset);
|
queue_buffer(buffer, samples, loop_index, time_offset);
|
||||||
if (_manager == 0) return;
|
if (_manager == 0) return;
|
||||||
|
fill += samples;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -866,17 +874,14 @@ get_name() const {
|
|||||||
// Description: Get status of the sound.
|
// Description: Get status of the sound.
|
||||||
//
|
//
|
||||||
// This returns the status as of the
|
// This returns the status as of the
|
||||||
// last AudioManager::update.
|
// last push_fresh_buffers
|
||||||
////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////
|
||||||
AudioSound::SoundStatus OpenALAudioSound::
|
AudioSound::SoundStatus OpenALAudioSound::
|
||||||
status() const {
|
status() const {
|
||||||
if (_source==0) {
|
if (_source==0) {
|
||||||
return AudioSound::READY;
|
return AudioSound::READY;
|
||||||
}
|
}
|
||||||
|
if (_loops_completed >= _playing_loops) {
|
||||||
_manager->make_current();
|
|
||||||
|
|
||||||
if (_stream_queued.size() == 0) {
|
|
||||||
return AudioSound::READY;
|
return AudioSound::READY;
|
||||||
} else {
|
} else {
|
||||||
return AudioSound::PLAYING;
|
return AudioSound::PLAYING;
|
||||||
|
@ -125,7 +125,7 @@ private:
|
|||||||
void restart_stalled_audio();
|
void restart_stalled_audio();
|
||||||
void delete_queued_buffers();
|
void delete_queued_buffers();
|
||||||
ALuint make_buffer(int samples, int channels, int rate, unsigned char *data);
|
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);
|
int read_stream_data(int bytelen, unsigned char *data);
|
||||||
void pull_used_buffers();
|
void pull_used_buffers();
|
||||||
void push_fresh_buffers();
|
void push_fresh_buffers();
|
||||||
@ -139,6 +139,7 @@ private:
|
|||||||
|
|
||||||
struct QueuedBuffer {
|
struct QueuedBuffer {
|
||||||
ALuint _buffer;
|
ALuint _buffer;
|
||||||
|
int _samples;
|
||||||
int _loop_index;
|
int _loop_index;
|
||||||
double _time_offset;
|
double _time_offset;
|
||||||
};
|
};
|
||||||
|
@ -53,6 +53,8 @@ init_libmovies() {
|
|||||||
MovieAudioCursor::init_type();
|
MovieAudioCursor::init_type();
|
||||||
InkblotVideo::init_type();
|
InkblotVideo::init_type();
|
||||||
InkblotVideoCursor::init_type();
|
InkblotVideoCursor::init_type();
|
||||||
|
UserDataAudio::init_type();
|
||||||
|
UserDataAudioCursor::init_type();
|
||||||
WebcamVideo::init_type();
|
WebcamVideo::init_type();
|
||||||
#ifdef HAVE_FFMPEG
|
#ifdef HAVE_FFMPEG
|
||||||
FfmpegVideo::init_type();
|
FfmpegVideo::init_type();
|
||||||
|
@ -50,39 +50,64 @@ audio_channels() const {
|
|||||||
////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////
|
||||||
// Function: MovieAudioCursor::length
|
// Function: MovieAudioCursor::length
|
||||||
// Access: Public
|
// 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,
|
// Some kinds of Movie, such as internet TV station,
|
||||||
// might not have a predictable length. In that case,
|
// might not have a predictable length. In that case,
|
||||||
// the length will be set to a very large number: 1.0E10.
|
// 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
|
// 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,
|
// short. When playing such an AVI using the Movie class,
|
||||||
// you may see a slightly truncated video, or a slightly
|
// you may see a slightly truncated video, or a slightly
|
||||||
// elongated video (padded with black frames). There are
|
// elongated video (padded with black frames). There are
|
||||||
// utilities out there to fix the length values in AVI
|
// utilities out there to fix the length values in AVI
|
||||||
// files.
|
// files.
|
||||||
//
|
//
|
||||||
|
// An audio consumer needs to check the length, the
|
||||||
|
// ready status, and the aborted flag.
|
||||||
////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////
|
||||||
INLINE double MovieAudioCursor::
|
INLINE double MovieAudioCursor::
|
||||||
length() const {
|
length() const {
|
||||||
return _length;
|
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
|
// Function: MovieAudioCursor::can_seek
|
||||||
// Access: Public
|
// Access: Public
|
||||||
@ -113,11 +138,9 @@ can_seek_fast() const {
|
|||||||
////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////
|
||||||
// Function: MovieAudioCursor::aborted
|
// Function: MovieAudioCursor::aborted
|
||||||
// Access: Public
|
// Access: Public
|
||||||
// Description: Returns true if the audio has aborted prematurely.
|
// Description: If aborted is true, it means that the "ready" samples
|
||||||
// For example, this could occur if the Movie was actually
|
// are not being replenished. See the method "ready"
|
||||||
// an internet TV station, and the connection was lost.
|
// for an explanation.
|
||||||
// Reaching the normal end of the audio does not
|
|
||||||
// constitute an 'abort' condition.
|
|
||||||
////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////
|
||||||
INLINE bool MovieAudioCursor::
|
INLINE bool MovieAudioCursor::
|
||||||
aborted() const {
|
aborted() const {
|
||||||
|
@ -36,6 +36,7 @@ MovieAudioCursor(MovieAudio *src) :
|
|||||||
_length(1.0E10),
|
_length(1.0E10),
|
||||||
_can_seek(true),
|
_can_seek(true),
|
||||||
_can_seek_fast(true),
|
_can_seek_fast(true),
|
||||||
|
_ready(0x40000000),
|
||||||
_aborted(false),
|
_aborted(false),
|
||||||
_samples_read(0)
|
_samples_read(0)
|
||||||
{
|
{
|
||||||
|
@ -53,6 +53,7 @@ PUBLISHED:
|
|||||||
INLINE bool aborted() const;
|
INLINE bool aborted() const;
|
||||||
INLINE double tell() const;
|
INLINE double tell() const;
|
||||||
INLINE void skip_samples(int n);
|
INLINE void skip_samples(int n);
|
||||||
|
INLINE int ready() const;
|
||||||
virtual void seek(double offset);
|
virtual void seek(double offset);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
@ -62,6 +63,7 @@ protected:
|
|||||||
PT(MovieAudio) _source;
|
PT(MovieAudio) _source;
|
||||||
int _audio_rate;
|
int _audio_rate;
|
||||||
int _audio_channels;
|
int _audio_channels;
|
||||||
|
int _ready;
|
||||||
double _length;
|
double _length;
|
||||||
bool _can_seek;
|
bool _can_seek;
|
||||||
bool _can_seek_fast;
|
bool _can_seek_fast;
|
||||||
|
@ -15,6 +15,9 @@
|
|||||||
|
|
||||||
#include "ffmpegVirtualFile.cxx"
|
#include "ffmpegVirtualFile.cxx"
|
||||||
|
|
||||||
|
#include "userDataAudio.cxx"
|
||||||
|
#include "userDataAudioCursor.cxx"
|
||||||
|
|
||||||
#include "webcamVideo.cxx"
|
#include "webcamVideo.cxx"
|
||||||
#include "webcamVideoDS.cxx"
|
#include "webcamVideoDS.cxx"
|
||||||
|
|
||||||
|
18
panda/src/movies/userDataAudio.I
Normal file
18
panda/src/movies/userDataAudio.I
Normal file
@ -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 .
|
||||||
|
//
|
||||||
|
////////////////////////////////////////////////////////////////////
|
||||||
|
|
144
panda/src/movies/userDataAudio.cxx
Normal file
144
panda/src/movies/userDataAudio.cxx
Normal file
@ -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<nread; i++) {
|
||||||
|
data[i] = _data[i];
|
||||||
|
}
|
||||||
|
for (int i=nread; i<n; i++) {
|
||||||
|
data[i] = 0;
|
||||||
|
}
|
||||||
|
for (int i=0; i<nread; i++) {
|
||||||
|
_data.pop_front();
|
||||||
|
}
|
||||||
|
update_cursor();
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////
|
||||||
|
// Function: UserDataAudio::append
|
||||||
|
// Access: Published
|
||||||
|
// Description: Appends audio samples to the buffer.
|
||||||
|
////////////////////////////////////////////////////////////////////
|
||||||
|
void UserDataAudio::
|
||||||
|
append(PN_int16 *data, int len) {
|
||||||
|
nassertv(!_aborted);
|
||||||
|
for (int i=0; i<len; i++) {
|
||||||
|
_data.push_back(data[i]);
|
||||||
|
}
|
||||||
|
update_cursor();
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////
|
||||||
|
// Function: UserDataAudio::append
|
||||||
|
// Access: Published
|
||||||
|
// Description: Appends audio samples to the buffer.
|
||||||
|
////////////////////////////////////////////////////////////////////
|
||||||
|
void UserDataAudio::
|
||||||
|
append(int val) {
|
||||||
|
nassertv(!_aborted);
|
||||||
|
PN_int16 truncated = (PN_int16)val;
|
||||||
|
nassertv(truncated == val);
|
||||||
|
_data.push_back(truncated);
|
||||||
|
update_cursor();
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////
|
||||||
|
// Function: UserDataAudio::done
|
||||||
|
// Access: Published
|
||||||
|
// Description: Promises not to append any more samples, ie, this
|
||||||
|
// marks the end of the audio stream.
|
||||||
|
////////////////////////////////////////////////////////////////////
|
||||||
|
void UserDataAudio::
|
||||||
|
done() {
|
||||||
|
_aborted = true;
|
||||||
|
update_cursor();
|
||||||
|
}
|
72
panda/src/movies/userDataAudio.h
Normal file
72
panda/src/movies/userDataAudio.h
Normal file
@ -0,0 +1,72 @@
|
|||||||
|
// Filename: userDataAudio.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 USERDATAAUDIO_H
|
||||||
|
#define USERDATAAUDIO_H
|
||||||
|
|
||||||
|
#include "movieAudio.h"
|
||||||
|
class MovieAudioCursor;
|
||||||
|
class UserDataAudioCursor;
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////
|
||||||
|
// Class : UserDataAudio
|
||||||
|
// Description : A UserDataAudio is a way for the user to manually
|
||||||
|
// supply raw audio samples.
|
||||||
|
////////////////////////////////////////////////////////////////////
|
||||||
|
class EXPCL_PANDA_MOVIES UserDataAudio : public MovieAudio {
|
||||||
|
|
||||||
|
PUBLISHED:
|
||||||
|
UserDataAudio(int rate, int channels);
|
||||||
|
virtual ~UserDataAudio();
|
||||||
|
virtual PT(MovieAudioCursor) open();
|
||||||
|
|
||||||
|
void append(PN_int16 *data, int len);
|
||||||
|
void append(int value); // Not fast enough, but useful for debugging.
|
||||||
|
void done(); // A promise not to write any more samples.
|
||||||
|
|
||||||
|
private:
|
||||||
|
void read_samples(int n, PN_int16 *data);
|
||||||
|
void update_cursor();
|
||||||
|
int _desired_rate;
|
||||||
|
int _desired_channels;
|
||||||
|
UserDataAudioCursor *_cursor;
|
||||||
|
pdeque<PN_int16> _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
|
18
panda/src/movies/userDataAudioCursor.I
Normal file
18
panda/src/movies/userDataAudioCursor.I
Normal file
@ -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 .
|
||||||
|
//
|
||||||
|
////////////////////////////////////////////////////////////////////
|
||||||
|
|
63
panda/src/movies/userDataAudioCursor.cxx
Normal file
63
panda/src/movies/userDataAudioCursor.cxx
Normal file
@ -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);
|
||||||
|
}
|
64
panda/src/movies/userDataAudioCursor.h
Normal file
64
panda/src/movies/userDataAudioCursor.h
Normal file
@ -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
|
Loading…
x
Reference in New Issue
Block a user