This commit is contained in:
Juan Linietsky 2015-09-10 00:12:05 -03:00
commit 3013a83f2f
25 changed files with 1443 additions and 513 deletions

View File

@ -1,7 +1,7 @@
#include "audio_stream_mpc.h" #include "audio_stream_mpc.h"
Error AudioStreamMPC::_open_file() { Error AudioStreamPlaybackMPC::_open_file() {
if (f) { if (f) {
memdelete(f); memdelete(f);
@ -41,7 +41,7 @@ Error AudioStreamMPC::_open_file() {
return OK; return OK;
} }
void AudioStreamMPC::_close_file() { void AudioStreamPlaybackMPC::_close_file() {
if (f) { if (f) {
memdelete(f); memdelete(f);
@ -52,7 +52,7 @@ void AudioStreamMPC::_close_file() {
data_ofs=0; data_ofs=0;
} }
int AudioStreamMPC::_read_file(void *p_dst,int p_bytes) { int AudioStreamPlaybackMPC::_read_file(void *p_dst,int p_bytes) {
if (f) if (f)
return f->get_buffer((uint8_t*)p_dst,p_bytes); return f->get_buffer((uint8_t*)p_dst,p_bytes);
@ -68,7 +68,7 @@ int AudioStreamMPC::_read_file(void *p_dst,int p_bytes) {
return p_bytes; return p_bytes;
} }
bool AudioStreamMPC::_seek_file(int p_pos){ bool AudioStreamPlaybackMPC::_seek_file(int p_pos){
if (p_pos<0 || p_pos>streamlen) if (p_pos<0 || p_pos>streamlen)
return false; return false;
@ -83,7 +83,7 @@ bool AudioStreamMPC::_seek_file(int p_pos){
return true; return true;
} }
int AudioStreamMPC::_tell_file() const{ int AudioStreamPlaybackMPC::_tell_file() const{
if (f) if (f)
return f->get_pos(); return f->get_pos();
@ -93,13 +93,13 @@ int AudioStreamMPC::_tell_file() const{
} }
int AudioStreamMPC::_sizeof_file() const{ int AudioStreamPlaybackMPC::_sizeof_file() const{
//print_line("sizeof file, get: "+itos(streamlen)); //print_line("sizeof file, get: "+itos(streamlen));
return streamlen; return streamlen;
} }
bool AudioStreamMPC::_canseek_file() const{ bool AudioStreamPlaybackMPC::_canseek_file() const{
//print_line("canseek file, get true"); //print_line("canseek file, get true");
return true; return true;
@ -107,51 +107,46 @@ bool AudioStreamMPC::_canseek_file() const{
///////////////////// /////////////////////
mpc_int32_t AudioStreamMPC::_mpc_read(mpc_reader *p_reader,void *p_dst, mpc_int32_t p_bytes) { mpc_int32_t AudioStreamPlaybackMPC::_mpc_read(mpc_reader *p_reader,void *p_dst, mpc_int32_t p_bytes) {
AudioStreamMPC *smpc=(AudioStreamMPC *)p_reader->data; AudioStreamPlaybackMPC *smpc=(AudioStreamPlaybackMPC *)p_reader->data;
return smpc->_read_file(p_dst,p_bytes); return smpc->_read_file(p_dst,p_bytes);
} }
mpc_bool_t AudioStreamMPC::_mpc_seek(mpc_reader *p_reader,mpc_int32_t p_offset) { mpc_bool_t AudioStreamPlaybackMPC::_mpc_seek(mpc_reader *p_reader,mpc_int32_t p_offset) {
AudioStreamMPC *smpc=(AudioStreamMPC *)p_reader->data; AudioStreamPlaybackMPC *smpc=(AudioStreamPlaybackMPC *)p_reader->data;
return smpc->_seek_file(p_offset); return smpc->_seek_file(p_offset);
} }
mpc_int32_t AudioStreamMPC::_mpc_tell(mpc_reader *p_reader) { mpc_int32_t AudioStreamPlaybackMPC::_mpc_tell(mpc_reader *p_reader) {
AudioStreamMPC *smpc=(AudioStreamMPC *)p_reader->data; AudioStreamPlaybackMPC *smpc=(AudioStreamPlaybackMPC *)p_reader->data;
return smpc->_tell_file(); return smpc->_tell_file();
} }
mpc_int32_t AudioStreamMPC::_mpc_get_size(mpc_reader *p_reader) { mpc_int32_t AudioStreamPlaybackMPC::_mpc_get_size(mpc_reader *p_reader) {
AudioStreamMPC *smpc=(AudioStreamMPC *)p_reader->data; AudioStreamPlaybackMPC *smpc=(AudioStreamPlaybackMPC *)p_reader->data;
return smpc->_sizeof_file(); return smpc->_sizeof_file();
} }
mpc_bool_t AudioStreamMPC::_mpc_canseek(mpc_reader *p_reader) { mpc_bool_t AudioStreamPlaybackMPC::_mpc_canseek(mpc_reader *p_reader) {
AudioStreamMPC *smpc=(AudioStreamMPC *)p_reader->data; AudioStreamPlaybackMPC *smpc=(AudioStreamPlaybackMPC *)p_reader->data;
return smpc->_canseek_file(); return smpc->_canseek_file();
} }
bool AudioStreamMPC::_can_mix() const {
return /*active &&*/ !paused; int AudioStreamPlaybackMPC::mix(int16_t* p_bufer,int p_frames) {
}
void AudioStreamMPC::update() {
if (!active || paused) if (!active || paused)
return; return 0;
int todo=get_todo(); int todo=p_frames;
while(todo>MPC_DECODER_BUFFER_LENGTH/si.channels) { while(todo>MPC_DECODER_BUFFER_LENGTH/si.channels) {
@ -162,7 +157,7 @@ void AudioStreamMPC::update() {
mpc_status err = mpc_demux_decode(demux, &frame); mpc_status err = mpc_demux_decode(demux, &frame);
if (frame.bits!=-1) { if (frame.bits!=-1) {
int16_t *dst_buff = get_write_buffer(); int16_t *dst_buff = p_bufer;
#ifdef MPC_FIXED_POINT #ifdef MPC_FIXED_POINT
@ -185,21 +180,21 @@ void AudioStreamMPC::update() {
#endif #endif
int frames = frame.samples; int frames = frame.samples;
write(frames); p_bufer+=si.channels*frames;
todo-=frames; todo-=frames;
} else { } else {
if (err != MPC_STATUS_OK) { if (err != MPC_STATUS_OK) {
stop(); stop();
ERR_EXPLAIN("Error decoding MPC"); ERR_PRINT("Error decoding MPC");
ERR_FAIL(); break;
} else { } else {
//finished //finished
if (!loop) { if (!loop) {
stop(); stop();
return; break;
} else { } else {
@ -213,9 +208,11 @@ void AudioStreamMPC::update() {
} }
} }
} }
return p_frames-todo;
} }
Error AudioStreamMPC::_reload() { Error AudioStreamPlaybackMPC::_reload() {
ERR_FAIL_COND_V(demux!=NULL, ERR_FILE_ALREADY_IN_USE); ERR_FAIL_COND_V(demux!=NULL, ERR_FILE_ALREADY_IN_USE);
@ -224,31 +221,40 @@ Error AudioStreamMPC::_reload() {
demux = mpc_demux_init(&reader); demux = mpc_demux_init(&reader);
ERR_FAIL_COND_V(!demux,ERR_CANT_CREATE); ERR_FAIL_COND_V(!demux,ERR_CANT_CREATE);
mpc_demux_get_info(demux, &si); mpc_demux_get_info(demux, &si);
_setup(si.channels,si.sample_freq,MPC_DECODER_BUFFER_LENGTH*2/si.channels);
return OK; return OK;
} }
void AudioStreamMPC::set_file(const String& p_file) { void AudioStreamPlaybackMPC::set_file(const String& p_file) {
file=p_file; file=p_file;
Error err = _open_file();
ERR_FAIL_COND(err!=OK);
demux = mpc_demux_init(&reader);
ERR_FAIL_COND(!demux);
mpc_demux_get_info(demux, &si);
stream_min_size=MPC_DECODER_BUFFER_LENGTH*2/si.channels;
stream_rate=si.sample_freq;
stream_channels=si.channels;
mpc_demux_exit(demux);
demux=NULL;
_close_file();
} }
String AudioStreamMPC::get_file() const { String AudioStreamPlaybackMPC::get_file() const {
return file; return file;
} }
void AudioStreamMPC::play() { void AudioStreamPlaybackMPC::play(float p_offset) {
_THREAD_SAFE_METHOD_
if (active) if (active)
stop(); stop();
active=false; active=false;
@ -262,9 +268,9 @@ void AudioStreamMPC::play() {
} }
void AudioStreamMPC::stop() { void AudioStreamPlaybackMPC::stop() {
_THREAD_SAFE_METHOD_
if (!active) if (!active)
return; return;
if (demux) { if (demux) {
@ -275,70 +281,58 @@ void AudioStreamMPC::stop() {
active=false; active=false;
} }
bool AudioStreamMPC::is_playing() const { bool AudioStreamPlaybackMPC::is_playing() const {
return active || (get_total() - get_todo() -1 > 0); return active;
} }
void AudioStreamMPC::set_paused(bool p_paused) {
paused=p_paused; void AudioStreamPlaybackMPC::set_loop(bool p_enable) {
}
bool AudioStreamMPC::is_paused(bool p_paused) const {
return paused;
}
void AudioStreamMPC::set_loop(bool p_enable) {
loop=p_enable; loop=p_enable;
} }
bool AudioStreamMPC::has_loop() const { bool AudioStreamPlaybackMPC::has_loop() const {
return loop; return loop;
} }
float AudioStreamMPC::get_length() const { float AudioStreamPlaybackMPC::get_length() const {
return 0; return 0;
} }
String AudioStreamMPC::get_stream_name() const { String AudioStreamPlaybackMPC::get_stream_name() const {
return ""; return "";
} }
int AudioStreamMPC::get_loop_count() const { int AudioStreamPlaybackMPC::get_loop_count() const {
return 0; return 0;
} }
float AudioStreamMPC::get_pos() const { float AudioStreamPlaybackMPC::get_pos() const {
return 0; return 0;
} }
void AudioStreamMPC::seek_pos(float p_time) { void AudioStreamPlaybackMPC::seek_pos(float p_time) {
} }
AudioStream::UpdateMode AudioStreamMPC::get_update_mode() const {
return UPDATE_THREAD; void AudioStreamPlaybackMPC::_bind_methods() {
}
void AudioStreamMPC::_bind_methods() { ObjectTypeDB::bind_method(_MD("set_file","name"),&AudioStreamPlaybackMPC::set_file);
ObjectTypeDB::bind_method(_MD("get_file"),&AudioStreamPlaybackMPC::get_file);
ObjectTypeDB::bind_method(_MD("set_file","name"),&AudioStreamMPC::set_file);
ObjectTypeDB::bind_method(_MD("get_file"),&AudioStreamMPC::get_file);
ADD_PROPERTYNZ( PropertyInfo(Variant::STRING,"file",PROPERTY_HINT_FILE,"mpc"), _SCS("set_file"), _SCS("get_file")); ADD_PROPERTYNZ( PropertyInfo(Variant::STRING,"file",PROPERTY_HINT_FILE,"mpc"), _SCS("set_file"), _SCS("get_file"));
} }
AudioStreamMPC::AudioStreamMPC() { AudioStreamPlaybackMPC::AudioStreamPlaybackMPC() {
preload=true; preload=false;
f=NULL; f=NULL;
streamlen=0; streamlen=0;
data_ofs=0; data_ofs=0;
@ -356,7 +350,7 @@ AudioStreamMPC::AudioStreamMPC() {
} }
AudioStreamMPC::~AudioStreamMPC() { AudioStreamPlaybackMPC::~AudioStreamPlaybackMPC() {
stop(); stop();

View File

@ -1,18 +1,17 @@
#ifndef AUDIO_STREAM_MPC_H #ifndef AUDIO_STREAM_MPC_H
#define AUDIO_STREAM_MPC_H #define AUDIO_STREAM_MPC_H
#include "scene/resources/audio_stream_resampled.h" #include "scene/resources/audio_stream.h"
#include "os/file_access.h" #include "os/file_access.h"
#include "mpc/mpcdec.h" #include "mpc/mpcdec.h"
#include "os/thread_safe.h" #include "os/thread_safe.h"
#include "io/resource_loader.h" #include "io/resource_loader.h"
//#include "../libmpcdec/decoder.h" //#include "../libmpcdec/decoder.h"
//#include "../libmpcdec/internal.h" //#include "../libmpcdec/internal.h"
class AudioStreamMPC : public AudioStreamResampled {
OBJ_TYPE( AudioStreamMPC, AudioStreamResampled ); class AudioStreamPlaybackMPC : public AudioStreamPlayback {
_THREAD_SAFE_CLASS_ OBJ_TYPE( AudioStreamPlaybackMPC, AudioStreamPlayback );
bool preload; bool preload;
FileAccess *f; FileAccess *f;
@ -39,7 +38,9 @@ class AudioStreamMPC : public AudioStreamResampled {
static mpc_int32_t _mpc_get_size(mpc_reader *p_reader); static mpc_int32_t _mpc_get_size(mpc_reader *p_reader);
static mpc_bool_t _mpc_canseek(mpc_reader *p_reader); static mpc_bool_t _mpc_canseek(mpc_reader *p_reader);
virtual bool _can_mix() const ; int stream_min_size;
int stream_rate;
int stream_channels;
protected: protected:
Error _open_file(); Error _open_file();
@ -59,12 +60,10 @@ public:
void set_file(const String& p_file); void set_file(const String& p_file);
String get_file() const; String get_file() const;
virtual void play(); virtual void play(float p_offset=0);
virtual void stop(); virtual void stop();
virtual bool is_playing() const; virtual bool is_playing() const;
virtual void set_paused(bool p_paused);
virtual bool is_paused(bool p_paused) const;
virtual void set_loop(bool p_enable); virtual void set_loop(bool p_enable);
virtual bool has_loop() const; virtual bool has_loop() const;
@ -78,13 +77,35 @@ public:
virtual float get_pos() const; virtual float get_pos() const;
virtual void seek_pos(float p_time); virtual void seek_pos(float p_time);
virtual UpdateMode get_update_mode() const; virtual int get_channels() const { return stream_channels; }
virtual void update(); virtual int get_mix_rate() const { return stream_rate; }
AudioStreamMPC(); virtual int get_minimum_buffer_size() const { return stream_min_size; }
~AudioStreamMPC(); virtual int mix(int16_t* p_bufer,int p_frames);
virtual void set_loop_restart_time(float p_time) { }
AudioStreamPlaybackMPC();
~AudioStreamPlaybackMPC();
}; };
class AudioStreamMPC : public AudioStream {
OBJ_TYPE( AudioStreamMPC, AudioStream );
String file;
public:
Ref<AudioStreamPlayback> instance_playback() {
Ref<AudioStreamPlaybackMPC> pb = memnew( AudioStreamPlaybackMPC );
pb->set_file(file);
return pb;
}
void set_file(const String& p_file) { file=p_file; }
};
class ResourceFormatLoaderAudioStreamMPC : public ResourceFormatLoader { class ResourceFormatLoaderAudioStreamMPC : public ResourceFormatLoader {
public: public:

View File

@ -15,14 +15,15 @@ static _FORCE_INLINE_ uint16_t le_short(uint16_t s)
} }
void AudioStreamSpeex::update() { int AudioStreamPlaybackSpeex::mix(int16_t* p_buffer,int p_frames) {
_THREAD_SAFE_METHOD_;
//printf("update, loops %i, read ofs %i\n", (int)loops, read_ofs); //printf("update, loops %i, read ofs %i\n", (int)loops, read_ofs);
//printf("playing %i, paused %i\n", (int)playing, (int)paused); //printf("playing %i, paused %i\n", (int)playing, (int)paused);
if (!active || !playing || paused || !data.size()) if (!active || !playing || paused || !data.size())
return; return 0;
/* /*
if (read_ofs >= data.size()) { if (read_ofs >= data.size()) {
@ -35,12 +36,13 @@ void AudioStreamSpeex::update() {
}; };
*/ */
int todo = get_todo(); int todo = p_frames;
if (todo < page_size) { if (todo < page_size) {
return; return 0;
}; };
int eos = 0; int eos = 0;
bool reloaded=false;
while (todo > page_size) { while (todo > page_size) {
@ -92,7 +94,7 @@ void AudioStreamSpeex::update() {
for (int j=0;j!=nframes;j++) for (int j=0;j!=nframes;j++)
{ {
int16_t* out = get_write_buffer(); int16_t* out = p_buffer;
int ret; int ret;
/*Decode frame*/ /*Decode frame*/
@ -120,7 +122,7 @@ void AudioStreamSpeex::update() {
/*Convert to short and save to output file*/ /*Convert to short and save to output file*/
for (int i=0;i<frame_size*get_channel_count();i++) { for (int i=0;i<frame_size*stream_channels;i++) {
out[i]=le_short(out[i]); out[i]=le_short(out[i]);
} }
@ -149,7 +151,7 @@ void AudioStreamSpeex::update() {
} }
write(new_frame_size); p_buffer+=new_frame_size*stream_channels;
todo-=new_frame_size; todo-=new_frame_size;
} }
} }
@ -175,6 +177,7 @@ void AudioStreamSpeex::update() {
if (loops) { if (loops) {
reload(); reload();
++loop_count; ++loop_count;
//break;
} else { } else {
playing=false; playing=false;
unload(); unload();
@ -183,18 +186,22 @@ void AudioStreamSpeex::update() {
} }
}; };
}; };
return p_frames-todo;
}; };
void AudioStreamSpeex::unload() { void AudioStreamPlaybackSpeex::unload() {
_THREAD_SAFE_METHOD_
if (!active) return; if (!active) return;
speex_bits_destroy(&bits); speex_bits_destroy(&bits);
if (st) if (st)
speex_decoder_destroy(st); speex_decoder_destroy(st);
ogg_sync_clear(&oy);
active = false; active = false;
//data.resize(0); //data.resize(0);
st = NULL; st = NULL;
@ -204,7 +211,7 @@ void AudioStreamSpeex::unload() {
loop_count = 0; loop_count = 0;
} }
void *AudioStreamSpeex::process_header(ogg_packet *op, int *frame_size, int *rate, int *nframes, int *channels, int *extra_headers) { void *AudioStreamPlaybackSpeex::process_header(ogg_packet *op, int *frame_size, int *rate, int *nframes, int *channels, int *extra_headers) {
void *st; void *st;
SpeexHeader *header; SpeexHeader *header;
@ -276,9 +283,9 @@ void *AudioStreamSpeex::process_header(ogg_packet *op, int *frame_size, int *rat
void AudioStreamSpeex::reload() { void AudioStreamPlaybackSpeex::reload() {
_THREAD_SAFE_METHOD_
if (active) if (active)
unload(); unload();
@ -359,8 +366,10 @@ void AudioStreamSpeex::reload() {
}; };
page_size = nframes * frame_size; page_size = nframes * frame_size;
stream_srate=rate;
stream_channels=channels;
stream_minbuff_size=page_size;
_setup(channels, rate,page_size);
} else if (packet_count==1) } else if (packet_count==1)
{ {
@ -374,23 +383,23 @@ void AudioStreamSpeex::reload() {
} while (packet_count <= extra_headers); } while (packet_count <= extra_headers);
active = true; active=true;
} }
void AudioStreamSpeex::_bind_methods() { void AudioStreamPlaybackSpeex::_bind_methods() {
ObjectTypeDB::bind_method(_MD("set_file","file"),&AudioStreamSpeex::set_file); //ObjectTypeDB::bind_method(_MD("set_file","file"),&AudioStreamPlaybackSpeex::set_file);
ObjectTypeDB::bind_method(_MD("get_file"),&AudioStreamSpeex::get_file); // ObjectTypeDB::bind_method(_MD("get_file"),&AudioStreamPlaybackSpeex::get_file);
ObjectTypeDB::bind_method(_MD("_set_bundled"),&AudioStreamSpeex::_set_bundled); ObjectTypeDB::bind_method(_MD("_set_bundled"),&AudioStreamPlaybackSpeex::_set_bundled);
ObjectTypeDB::bind_method(_MD("_get_bundled"),&AudioStreamSpeex::_get_bundled); ObjectTypeDB::bind_method(_MD("_get_bundled"),&AudioStreamPlaybackSpeex::_get_bundled);
ADD_PROPERTY( PropertyInfo(Variant::DICTIONARY,"_bundled",PROPERTY_HINT_NONE,"",PROPERTY_USAGE_BUNDLE),_SCS("_set_bundled"),_SCS("_get_bundled")); ADD_PROPERTY( PropertyInfo(Variant::DICTIONARY,"_bundled",PROPERTY_HINT_NONE,"",PROPERTY_USAGE_BUNDLE),_SCS("_set_bundled"),_SCS("_get_bundled"));
ADD_PROPERTY( PropertyInfo(Variant::STRING,"file",PROPERTY_HINT_FILE,"*.spx"),_SCS("set_file"),_SCS("get_file")); //ADD_PROPERTY( PropertyInfo(Variant::STRING,"file",PROPERTY_HINT_FILE,"*.spx"),_SCS("set_file"),_SCS("get_file"));
}; };
void AudioStreamSpeex::_set_bundled(const Dictionary& dict) { void AudioStreamPlaybackSpeex::_set_bundled(const Dictionary& dict) {
ERR_FAIL_COND( !dict.has("filename")); ERR_FAIL_COND( !dict.has("filename"));
ERR_FAIL_COND( !dict.has("data")); ERR_FAIL_COND( !dict.has("data"));
@ -399,7 +408,7 @@ void AudioStreamSpeex::_set_bundled(const Dictionary& dict) {
data = dict["data"]; data = dict["data"];
}; };
Dictionary AudioStreamSpeex::_get_bundled() const { Dictionary AudioStreamPlaybackSpeex::_get_bundled() const {
Dictionary d; Dictionary d;
d["filename"] = filename; d["filename"] = filename;
@ -408,19 +417,101 @@ Dictionary AudioStreamSpeex::_get_bundled() const {
}; };
String AudioStreamSpeex::get_file() const {
return filename; void AudioStreamPlaybackSpeex::set_data(const Vector<uint8_t>& p_data) {
data=p_data;
reload();
}
void AudioStreamPlaybackSpeex::play(float p_from_pos) {
reload();
if (!active)
return;
playing = true;
}
void AudioStreamPlaybackSpeex::stop(){
unload();
playing = false;
}
bool AudioStreamPlaybackSpeex::is_playing() const{
return playing;
}
void AudioStreamPlaybackSpeex::set_loop(bool p_enable){
loops = p_enable;
}
bool AudioStreamPlaybackSpeex::has_loop() const{
return loops;
}
float AudioStreamPlaybackSpeex::get_length() const{
return 0;
}
String AudioStreamPlaybackSpeex::get_stream_name() const{
return "";
}
int AudioStreamPlaybackSpeex::get_loop_count() const{
return 0;
}
float AudioStreamPlaybackSpeex::get_pos() const{
return 0;
}
void AudioStreamPlaybackSpeex::seek_pos(float p_time){
}; };
void AudioStreamSpeex::set_file(const String& p_file){
if (filename == p_file)
AudioStreamPlaybackSpeex::AudioStreamPlaybackSpeex() {
active=false;
st = NULL;
stream_channels=1;
stream_srate=1;
stream_minbuff_size=1;
}
AudioStreamPlaybackSpeex::~AudioStreamPlaybackSpeex() {
unload();
}
////////////////////////////////////////
void AudioStreamSpeex::set_file(const String& p_file) {
if (this->file == p_file)
return; return;
if (active) { this->file=p_file;
unload();
}
if (p_file == "") { if (p_file == "") {
data.resize(0); data.resize(0);
@ -434,100 +525,11 @@ void AudioStreamSpeex::set_file(const String& p_file){
}; };
ERR_FAIL_COND(err != OK); ERR_FAIL_COND(err != OK);
filename = p_file; this->file = p_file;
data.resize(file->get_len()); data.resize(file->get_len());
int read = file->get_buffer(&data[0], data.size()); int read = file->get_buffer(&data[0], data.size());
memdelete(file); memdelete(file);
reload();
}
void AudioStreamSpeex::play() {
_THREAD_SAFE_METHOD_
reload();
if (!active)
return;
playing = true;
}
void AudioStreamSpeex::stop(){
_THREAD_SAFE_METHOD_
unload();
playing = false;
_clear();
}
bool AudioStreamSpeex::is_playing() const{
return _is_ready() && (playing || (get_total() - get_todo() -1 > 0));
}
void AudioStreamSpeex::set_paused(bool p_paused){
playing = !p_paused;
paused = p_paused;
}
bool AudioStreamSpeex::is_paused(bool p_paused) const{
return paused;
}
void AudioStreamSpeex::set_loop(bool p_enable){
loops = p_enable;
}
bool AudioStreamSpeex::has_loop() const{
return loops;
}
float AudioStreamSpeex::get_length() const{
return 0;
}
String AudioStreamSpeex::get_stream_name() const{
return "";
}
int AudioStreamSpeex::get_loop_count() const{
return 0;
}
float AudioStreamSpeex::get_pos() const{
return 0;
}
void AudioStreamSpeex::seek_pos(float p_time){
};
bool AudioStreamSpeex::_can_mix() const {
//return playing;
return data.size() != 0;
};
AudioStream::UpdateMode AudioStreamSpeex::get_update_mode() const {
return UPDATE_THREAD;
}
AudioStreamSpeex::AudioStreamSpeex() {
active=false;
st = NULL;
}
AudioStreamSpeex::~AudioStreamSpeex() {
unload();
} }
RES ResourceFormatLoaderAudioStreamSpeex::load(const String &p_path, const String& p_original_path, Error *r_error) { RES ResourceFormatLoaderAudioStreamSpeex::load(const String &p_path, const String& p_original_path, Error *r_error) {

View File

@ -1,7 +1,7 @@
#ifndef AUDIO_STREAM_SPEEX_H #ifndef AUDIO_STREAM_SPEEX_H
#define AUDIO_STREAM_SPEEX_H #define AUDIO_STREAM_SPEEX_H
#include "scene/resources/audio_stream_resampled.h" #include "scene/resources/audio_stream.h"
#include "speex/speex.h" #include "speex/speex.h"
#include "os/file_access.h" #include "os/file_access.h"
#include "io/resource_loader.h" #include "io/resource_loader.h"
@ -14,10 +14,10 @@
#include <ogg/ogg.h> #include <ogg/ogg.h>
class AudioStreamSpeex : public AudioStreamResampled { class AudioStreamPlaybackSpeex : public AudioStreamPlayback {
OBJ_TYPE(AudioStreamPlaybackSpeex, AudioStreamPlayback);
OBJ_TYPE(AudioStreamSpeex, AudioStreamResampled);
_THREAD_SAFE_CLASS_
void *st; void *st;
SpeexBits bits; SpeexBits bits;
@ -45,6 +45,9 @@ class AudioStreamSpeex : public AudioStreamResampled {
ogg_int64_t page_granule, last_granule; ogg_int64_t page_granule, last_granule;
int skip_samples, page_nb_packets; int skip_samples, page_nb_packets;
int stream_channels;
int stream_srate;
int stream_minbuff_size;
void* process_header(ogg_packet *op, int *frame_size, int *rate, int *nframes, int *channels, int *extra_headers); void* process_header(ogg_packet *op, int *frame_size, int *rate, int *nframes, int *channels, int *extra_headers);
@ -52,7 +55,7 @@ class AudioStreamSpeex : public AudioStreamResampled {
protected: protected:
virtual bool _can_mix() const; //virtual bool _can_mix() const;
Dictionary _get_bundled() const; Dictionary _get_bundled() const;
void _set_bundled(const Dictionary& dict); void _set_bundled(const Dictionary& dict);
@ -60,16 +63,12 @@ protected:
public: public:
void set_file(const String& p_file); void set_data(const Vector<uint8_t>& p_data);
String get_file() const;
virtual void play(); virtual void play(float p_from_pos=0);
virtual void stop(); virtual void stop();
virtual bool is_playing() const; virtual bool is_playing() const;
virtual void set_paused(bool p_paused);
virtual bool is_paused(bool p_paused) const;
virtual void set_loop(bool p_enable); virtual void set_loop(bool p_enable);
virtual bool has_loop() const; virtual bool has_loop() const;
@ -82,13 +81,39 @@ public:
virtual float get_pos() const; virtual float get_pos() const;
virtual void seek_pos(float p_time); virtual void seek_pos(float p_time);
virtual UpdateMode get_update_mode() const; virtual int get_channels() const { return stream_channels; }
virtual void update(); virtual int get_mix_rate() const { return stream_srate; }
AudioStreamSpeex(); virtual int get_minimum_buffer_size() const { return stream_minbuff_size; }
~AudioStreamSpeex(); virtual int mix(int16_t* p_bufer,int p_frames);
virtual void set_loop_restart_time(float p_time) { } //no loop restart, ignore
AudioStreamPlaybackSpeex();
~AudioStreamPlaybackSpeex();
}; };
class AudioStreamSpeex : public AudioStream {
OBJ_TYPE(AudioStreamSpeex,AudioStream);
Vector<uint8_t> data;
String file;
public:
Ref<AudioStreamPlayback> instance_playback() {
Ref<AudioStreamPlaybackSpeex> pb = memnew( AudioStreamPlaybackSpeex );
pb->set_data(data);
return pb;
}
void set_file(const String& p_file);
};
class ResourceFormatLoaderAudioStreamSpeex : public ResourceFormatLoader { class ResourceFormatLoaderAudioStreamSpeex : public ResourceFormatLoader {
public: public:
virtual RES load(const String &p_path,const String& p_original_path="",Error *r_error=NULL); virtual RES load(const String &p_path,const String& p_original_path="",Error *r_error=NULL);

View File

@ -226,7 +226,8 @@ uint64_t OS_Unix::get_unix_time() const {
uint64_t OS_Unix::get_system_time_msec() const { uint64_t OS_Unix::get_system_time_msec() const {
struct timeval tv_now; struct timeval tv_now;
gettimeofday(&tv_now, NULL); gettimeofday(&tv_now, NULL);
localtime(&tv_now.tv_usec); //localtime(&tv_now.tv_usec);
localtime((const long *)&tv_now.tv_usec);
uint64_t msec = tv_now.tv_usec/1000; uint64_t msec = tv_now.tv_usec/1000;
return msec; return msec;
} }

View File

@ -30,7 +30,7 @@
size_t AudioStreamOGGVorbis::_ov_read_func(void *p_dst,size_t p_data, size_t p_count, void *_f) { size_t AudioStreamPlaybackOGGVorbis::_ov_read_func(void *p_dst,size_t p_data, size_t p_count, void *_f) {
//printf("read to %p, %i bytes, %i nmemb, %p\n",p_dst,p_data,p_count,_f); //printf("read to %p, %i bytes, %i nmemb, %p\n",p_dst,p_data,p_count,_f);
FileAccess *fa=(FileAccess*)_f; FileAccess *fa=(FileAccess*)_f;
@ -46,7 +46,7 @@ size_t AudioStreamOGGVorbis::_ov_read_func(void *p_dst,size_t p_data, size_t p_c
return read; return read;
} }
int AudioStreamOGGVorbis::_ov_seek_func(void *_f,ogg_int64_t offs, int whence) { int AudioStreamPlaybackOGGVorbis::_ov_seek_func(void *_f,ogg_int64_t offs, int whence) {
//printf("seek to %p, offs %i, whence %i\n",_f,(int)offs,whence); //printf("seek to %p, offs %i, whence %i\n",_f,(int)offs,whence);
@ -76,7 +76,7 @@ int AudioStreamOGGVorbis::_ov_seek_func(void *_f,ogg_int64_t offs, int whence) {
#endif #endif
} }
int AudioStreamOGGVorbis::_ov_close_func(void *_f) { int AudioStreamPlaybackOGGVorbis::_ov_close_func(void *_f) {
// printf("close %p\n",_f); // printf("close %p\n",_f);
if (!_f) if (!_f)
@ -86,7 +86,7 @@ int AudioStreamOGGVorbis::_ov_close_func(void *_f) {
fa->close(); fa->close();
return 0; return 0;
} }
long AudioStreamOGGVorbis::_ov_tell_func(void *_f) { long AudioStreamPlaybackOGGVorbis::_ov_tell_func(void *_f) {
//printf("close %p\n",_f); //printf("close %p\n",_f);
@ -95,38 +95,32 @@ long AudioStreamOGGVorbis::_ov_tell_func(void *_f) {
} }
bool AudioStreamOGGVorbis::_can_mix() const {
return /*playing &&*/ !paused; int AudioStreamPlaybackOGGVorbis::mix(int16_t* p_bufer,int p_frames) {
}
if (!playing)
return 0;
void AudioStreamOGGVorbis::update() { int total=p_frames;
_THREAD_SAFE_METHOD_
if (!playing && !setting_up)
return;
while (true) { while (true) {
int todo = get_todo(); int todo = p_frames;
if (todo==0 || todo<MIN_MIX) if (todo==0 || todo<MIN_MIX) {
break; break;
}
//printf("to mix %i - mix me %i bytes\n",to_mix,to_mix*stream_channels*sizeof(int16_t)); //printf("to mix %i - mix me %i bytes\n",to_mix,to_mix*stream_channels*sizeof(int16_t));
#ifdef BIG_ENDIAN_ENABLED #ifdef BIG_ENDIAN_ENABLED
long ret=ov_read(&vf,(char*)get_write_buffer(),todo*stream_channels*sizeof(int16_t), 1, 2, 1, &current_section); long ret=ov_read(&vf,(char*)p_bufer,todo*stream_channels*sizeof(int16_t), 1, 2, 1, &current_section);
#else #else
long ret=ov_read(&vf,(char*)get_write_buffer(),todo*stream_channels*sizeof(int16_t), 0, 2, 1, &current_section); long ret=ov_read(&vf,(char*)p_bufer,todo*stream_channels*sizeof(int16_t), 0, 2, 1, &current_section);
#endif #endif
if (ret<0) { if (ret<0) {
playing = false; playing = false;
setting_up=false;
ERR_EXPLAIN("Error reading OGG Vorbis File: "+file); ERR_EXPLAIN("Error reading OGG Vorbis File: "+file);
ERR_BREAK(ret<0); ERR_BREAK(ret<0);
} else if (ret==0) { // end of song, reload? } else if (ret==0) { // end of song, reload?
@ -138,9 +132,8 @@ void AudioStreamOGGVorbis::update() {
if (!has_loop()) { if (!has_loop()) {
playing=false; playing=false;
setting_up=false;
repeats=1; repeats=1;
return; break;
} }
f=FileAccess::open(file,FileAccess::READ); f=FileAccess::open(file,FileAccess::READ);
@ -148,11 +141,22 @@ void AudioStreamOGGVorbis::update() {
int errv = ov_open_callbacks(f,&vf,NULL,0,_ov_callbacks); int errv = ov_open_callbacks(f,&vf,NULL,0,_ov_callbacks);
if (errv!=0) { if (errv!=0) {
playing=false; playing=false;
setting_up=false; break;; // :(
return; // :(
} }
frames_mixed=0; if (loop_restart_time) {
bool ok = ov_time_seek(&vf,loop_restart_time)==0;
if (!ok) {
playing=false;
//ERR_EXPLAIN("loop restart time rejected");
ERR_PRINT("loop restart time rejected")
}
frames_mixed=stream_srate*loop_restart_time;
} else {
frames_mixed=0;
}
repeats++; repeats++;
continue; continue;
@ -162,16 +166,19 @@ void AudioStreamOGGVorbis::update() {
ret/=sizeof(int16_t); ret/=sizeof(int16_t);
frames_mixed+=ret; frames_mixed+=ret;
write(ret);
p_bufer+=ret*stream_channels;
p_frames-=ret;
} }
return total-p_frames;
} }
void AudioStreamOGGVorbis::play() { void AudioStreamPlaybackOGGVorbis::play(float p_from) {
_THREAD_SAFE_METHOD_
if (playing) if (playing)
stop(); stop();
@ -179,56 +186,46 @@ void AudioStreamOGGVorbis::play() {
if (_load_stream()!=OK) if (_load_stream()!=OK)
return; return;
frames_mixed=0; frames_mixed=0;
playing=false;
setting_up=true;
update();
if (!setting_up)
return;
setting_up=false;
playing=true; playing=true;
if (p_from>0) {
seek_pos(p_from);
}
} }
void AudioStreamOGGVorbis::_close_file() { void AudioStreamPlaybackOGGVorbis::_close_file() {
if (f) { if (f) {
memdelete(f); memdelete(f);
f=NULL; f=NULL;
} }
} }
void AudioStreamOGGVorbis::stop() { bool AudioStreamPlaybackOGGVorbis::is_playing() const {
return playing;
_THREAD_SAFE_METHOD_ }
void AudioStreamPlaybackOGGVorbis::stop() {
_clear_stream(); _clear_stream();
playing=false; playing=false;
_clear(); //_clear();
}
AudioStreamOGGVorbis::UpdateMode AudioStreamOGGVorbis::get_update_mode() const {
return UPDATE_THREAD;
} }
bool AudioStreamOGGVorbis::is_playing() const {
float AudioStreamPlaybackOGGVorbis::get_pos() const {
return playing || (get_total() - get_todo() -1 > 0); int32_t frames = int32_t(frames_mixed);
}
float AudioStreamOGGVorbis::get_pos() const {
int32_t frames = int32_t(frames_mixed) - (int32_t(get_total()) - get_todo());
if (frames < 0) if (frames < 0)
frames=0; frames=0;
return double(frames) / stream_srate; return double(frames) / stream_srate;
} }
void AudioStreamOGGVorbis::seek_pos(float p_time) { void AudioStreamPlaybackOGGVorbis::seek_pos(float p_time) {
_THREAD_SAFE_METHOD_
if (!playing) if (!playing)
return; return;
@ -237,32 +234,75 @@ void AudioStreamOGGVorbis::seek_pos(float p_time) {
frames_mixed=stream_srate*p_time; frames_mixed=stream_srate*p_time;
} }
String AudioStreamOGGVorbis::get_stream_name() const { String AudioStreamPlaybackOGGVorbis::get_stream_name() const {
return ""; return "";
} }
void AudioStreamOGGVorbis::set_loop(bool p_enable) { void AudioStreamPlaybackOGGVorbis::set_loop(bool p_enable) {
loops=p_enable; loops=p_enable;
} }
bool AudioStreamOGGVorbis::has_loop() const { bool AudioStreamPlaybackOGGVorbis::has_loop() const {
return loops; return loops;
} }
int AudioStreamOGGVorbis::get_loop_count() const { int AudioStreamPlaybackOGGVorbis::get_loop_count() const {
return repeats; return repeats;
} }
void AudioStreamOGGVorbis::set_file(const String& p_file) { Error AudioStreamPlaybackOGGVorbis::set_file(const String& p_file) {
file=p_file; file=p_file;
stream_valid=false;
Error err;
f=FileAccess::open(file,FileAccess::READ,&err);
if (err) {
ERR_FAIL_COND_V( err, err );
}
int errv = ov_open_callbacks(f,&vf,NULL,0,_ov_callbacks);
switch(errv) {
case OV_EREAD: { // - A read from media returned an error.
memdelete(f); f=NULL;
ERR_FAIL_V( ERR_FILE_CANT_READ );
} break;
case OV_EVERSION: // - Vorbis version mismatch.
case OV_ENOTVORBIS: { // - Bitstream is not Vorbis data.
memdelete(f); f=NULL;
ERR_FAIL_V( ERR_FILE_UNRECOGNIZED );
} break;
case OV_EBADHEADER: { // - Invalid Vorbis bitstream header.
memdelete(f); f=NULL;
ERR_FAIL_V( ERR_FILE_CORRUPT );
} break;
case OV_EFAULT: { // - Internal logic fault; indicates a bug or heap/stack corruption.
memdelete(f); f=NULL;
ERR_FAIL_V( ERR_BUG );
} break;
}
const vorbis_info *vinfo=ov_info(&vf,-1);
stream_channels=vinfo->channels;
stream_srate=vinfo->rate;
ogg_int64_t len = ov_time_total(&vf,-1);
length=len/1000.0;
ov_clear(&vf);
memdelete(f);
f=NULL;
stream_valid=true;
return OK;
} }
Error AudioStreamOGGVorbis::_load_stream() { Error AudioStreamPlaybackOGGVorbis::_load_stream() {
ERR_FAIL_COND_V(!stream_valid,ERR_UNCONFIGURED);
_clear_stream(); _clear_stream();
if (file=="") if (file=="")
@ -270,52 +310,31 @@ Error AudioStreamOGGVorbis::_load_stream() {
Error err; Error err;
f=FileAccess::open(file,FileAccess::READ,&err); f=FileAccess::open(file,FileAccess::READ,&err);
if (err) { if (err) {
ERR_FAIL_COND_V( err, err ); ERR_FAIL_COND_V( err, err );
} }
int errv = ov_open_callbacks(f,&vf,NULL,0,_ov_callbacks); int errv = ov_open_callbacks(f,&vf,NULL,0,_ov_callbacks);
const vorbis_info *vinfo=ov_info(&vf,-1);
stream_channels=vinfo->channels;
stream_srate=vinfo->rate;
Error serr = _setup(stream_channels,stream_srate);
if (serr) {
_close_file();
ERR_FAIL_V( ERR_INVALID_DATA );
}
switch(errv) { switch(errv) {
case OV_EREAD: { // - A read from media returned an error. case OV_EREAD: { // - A read from media returned an error.
_close_file(); memdelete(f); f=NULL;
ERR_FAIL_V( ERR_FILE_CANT_READ ); ERR_FAIL_V( ERR_FILE_CANT_READ );
} break; } break;
case OV_EVERSION: // - Vorbis version mismatch. case OV_EVERSION: // - Vorbis version mismatch.
case OV_ENOTVORBIS: { // - Bitstream is not Vorbis data. case OV_ENOTVORBIS: { // - Bitstream is not Vorbis data.
_close_file(); memdelete(f); f=NULL;
ERR_FAIL_V( ERR_FILE_UNRECOGNIZED ); ERR_FAIL_V( ERR_FILE_UNRECOGNIZED );
} break; } break;
case OV_EBADHEADER: { // - Invalid Vorbis bitstream header. case OV_EBADHEADER: { // - Invalid Vorbis bitstream header.
_close_file(); memdelete(f); f=NULL;
ERR_FAIL_V( ERR_FILE_CORRUPT ); ERR_FAIL_V( ERR_FILE_CORRUPT );
} break; } break;
case OV_EFAULT: { // - Internal logic fault; indicates a bug or heap/stack corruption. case OV_EFAULT: { // - Internal logic fault; indicates a bug or heap/stack corruption.
memdelete(f); f=NULL;
_close_file();
ERR_FAIL_V( ERR_BUG ); ERR_FAIL_V( ERR_BUG );
} break; } break;
} }
ogg_int64_t len = ov_time_total(&vf,-1);
length=len/1000.0;
repeats=0; repeats=0;
stream_loaded=true; stream_loaded=true;
@ -324,16 +343,16 @@ Error AudioStreamOGGVorbis::_load_stream() {
} }
float AudioStreamOGGVorbis::get_length() const { float AudioStreamPlaybackOGGVorbis::get_length() const {
if (!stream_loaded) { if (!stream_loaded) {
if (const_cast<AudioStreamOGGVorbis*>(this)->_load_stream()!=OK) if (const_cast<AudioStreamPlaybackOGGVorbis*>(this)->_load_stream()!=OK)
return 0; return 0;
} }
return length; return length;
} }
void AudioStreamOGGVorbis::_clear_stream() { void AudioStreamPlaybackOGGVorbis::_clear_stream() {
if (!stream_loaded) if (!stream_loaded)
return; return;
@ -346,18 +365,18 @@ void AudioStreamOGGVorbis::_clear_stream() {
playing=false; playing=false;
} }
void AudioStreamOGGVorbis::set_paused(bool p_paused) { void AudioStreamPlaybackOGGVorbis::set_paused(bool p_paused) {
paused=p_paused; paused=p_paused;
} }
bool AudioStreamOGGVorbis::is_paused(bool p_paused) const { bool AudioStreamPlaybackOGGVorbis::is_paused(bool p_paused) const {
return paused; return paused;
} }
AudioStreamOGGVorbis::AudioStreamOGGVorbis() { AudioStreamPlaybackOGGVorbis::AudioStreamPlaybackOGGVorbis() {
loops=false; loops=false;
playing=false; playing=false;
@ -367,17 +386,18 @@ AudioStreamOGGVorbis::AudioStreamOGGVorbis() {
_ov_callbacks.tell_func=_ov_tell_func; _ov_callbacks.tell_func=_ov_tell_func;
f = NULL; f = NULL;
stream_loaded=false; stream_loaded=false;
repeats=0; stream_valid=false;
setting_up=false; repeats=0;
paused=true; paused=true;
stream_channels=0; stream_channels=0;
stream_srate=0; stream_srate=0;
current_section=0; current_section=0;
length=0; length=0;
loop_restart_time=0;
} }
AudioStreamOGGVorbis::~AudioStreamOGGVorbis() { AudioStreamPlaybackOGGVorbis::~AudioStreamPlaybackOGGVorbis() {
_clear_stream(); _clear_stream();

View File

@ -29,17 +29,16 @@
#ifndef AUDIO_STREAM_OGG_VORBIS_H #ifndef AUDIO_STREAM_OGG_VORBIS_H
#define AUDIO_STREAM_OGG_VORBIS_H #define AUDIO_STREAM_OGG_VORBIS_H
#include "scene/resources/audio_stream_resampled.h" #include "scene/resources/audio_stream.h"
#include "vorbis/vorbisfile.h" #include "vorbis/vorbisfile.h"
#include "os/file_access.h" #include "os/file_access.h"
#include "io/resource_loader.h" #include "io/resource_loader.h"
#include "os/thread_safe.h" #include "os/thread_safe.h"
class AudioStreamOGGVorbis : public AudioStreamResampled {
OBJ_TYPE(AudioStreamOGGVorbis,AudioStreamResampled); class AudioStreamPlaybackOGGVorbis : public AudioStreamPlayback {
_THREAD_SAFE_CLASS_
OBJ_TYPE(AudioStreamPlaybackOGGVorbis,AudioStreamPlayback);
enum { enum {
MIN_MIX=1024 MIN_MIX=1024
@ -54,9 +53,6 @@ class AudioStreamOGGVorbis : public AudioStreamResampled {
static int _ov_close_func(void *_f); static int _ov_close_func(void *_f);
static long _ov_tell_func(void *_f); static long _ov_tell_func(void *_f);
virtual bool _can_mix() const;
String file; String file;
int64_t frames_mixed; int64_t frames_mixed;
@ -67,7 +63,7 @@ class AudioStreamOGGVorbis : public AudioStreamResampled {
int stream_srate; int stream_srate;
int current_section; int current_section;
volatile bool setting_up;
bool paused; bool paused;
bool loops; bool loops;
int repeats; int repeats;
@ -76,17 +72,21 @@ class AudioStreamOGGVorbis : public AudioStreamResampled {
void _clear_stream(); void _clear_stream();
void _close_file(); void _close_file();
bool stream_valid;
float loop_restart_time;
public: public:
void set_file(const String& p_file); Error set_file(const String& p_file);
virtual void play(float p_from=0);
virtual void play();
virtual void stop(); virtual void stop();
virtual bool is_playing() const; virtual bool is_playing() const;
virtual void set_loop_restart_time(float p_time) { loop_restart_time=0; }
virtual void set_paused(bool p_paused); virtual void set_paused(bool p_paused);
virtual bool is_paused(bool p_paused) const; virtual bool is_paused(bool p_paused) const;
@ -102,11 +102,32 @@ public:
virtual float get_pos() const; virtual float get_pos() const;
virtual void seek_pos(float p_time); virtual void seek_pos(float p_time);
virtual UpdateMode get_update_mode() const; virtual int get_channels() const { return stream_channels; }
virtual void update(); virtual int get_mix_rate() const { return stream_srate; }
virtual int get_minimum_buffer_size() const { return 0; }
virtual int mix(int16_t* p_bufer,int p_frames);
AudioStreamPlaybackOGGVorbis();
~AudioStreamPlaybackOGGVorbis();
};
class AudioStreamOGGVorbis : public AudioStream {
OBJ_TYPE(AudioStreamOGGVorbis,AudioStream);
String file;
public:
Ref<AudioStreamPlayback> instance_playback() {
Ref<AudioStreamPlaybackOGGVorbis> pb = memnew( AudioStreamPlaybackOGGVorbis );
pb->set_file(file);
return pb;
}
void set_file(const String& p_file) { file=p_file; }
AudioStreamOGGVorbis();
~AudioStreamOGGVorbis();
}; };
class ResourceFormatLoaderAudioStreamOGGVorbis : public ResourceFormatLoader { class ResourceFormatLoaderAudioStreamOGGVorbis : public ResourceFormatLoader {

View File

@ -339,7 +339,6 @@ Error Main::setup(const char *execpath,int argc, char *argv[],bool p_second_phas
init_custom_pos=Point2(x,y); init_custom_pos=Point2(x,y);
init_use_custom_pos=true; init_use_custom_pos=true;
force_res=true;
N=I->next()->next(); N=I->next()->next();
} else { } else {

View File

@ -34,5 +34,5 @@ obj = env_ios.Object('godot_iphone.cpp')
prog = None prog = None
prog = env_ios.Program('#bin/godot', [obj] + iphone_lib) prog = env_ios.Program('#bin/godot', [obj] + iphone_lib)
action = "dsymutil "+File(prog)[0].path+" -o " + File(prog)[0].path + ".dSYM" action = "$IPHONEPATH/usr/bin/dsymutil "+File(prog)[0].path+" -o " + File(prog)[0].path + ".dSYM"
env.AddPostAction(prog, action) env.AddPostAction(prog, action)

View File

@ -11,7 +11,8 @@ def get_name():
def can_build(): def can_build():
import sys import sys
if sys.platform == 'darwin': import os
if sys.platform == 'darwin' or os.environ.has_key("OSXCROSS_IOS"):
return True return True
return False return False
@ -28,6 +29,7 @@ def get_opts():
('ios_gles22_override', 'Force GLES2.0 on iOS', 'yes'), ('ios_gles22_override', 'Force GLES2.0 on iOS', 'yes'),
('ios_appirater', 'Enable Appirater', 'no'), ('ios_appirater', 'Enable Appirater', 'no'),
('ios_exceptions', 'Use exceptions when compiling on playbook', 'yes'), ('ios_exceptions', 'Use exceptions when compiling on playbook', 'yes'),
('ios_triple', 'Triple for ios toolchain', ''),
] ]
def get_flags(): def get_flags():
@ -48,9 +50,10 @@ def configure(env):
# env['CC'] = '$IPHONEPATH/Developer/usr/bin/gcc' # env['CC'] = '$IPHONEPATH/Developer/usr/bin/gcc'
# env['CXX'] = '$IPHONEPATH/Developer/usr/bin/g++' # env['CXX'] = '$IPHONEPATH/Developer/usr/bin/g++'
env['CC'] = '$IPHONEPATH/usr/bin/clang' env['CC'] = '$IPHONEPATH/usr/bin/${ios_triple}clang'
env['CXX'] = '$IPHONEPATH/usr/bin/clang++' env['CXX'] = '$IPHONEPATH/usr/bin/${ios_triple}clang++'
env['AR'] = 'ar' env['AR'] = '$IPHONEPATH/usr/bin/${ios_triple}ar'
env['RANLIB'] = '$IPHONEPATH/usr/bin/${ios_triple}ranlib'
import string import string
if (env["bits"]=="64"): if (env["bits"]=="64"):

View File

@ -30,21 +30,79 @@
int SpatialStreamPlayer::InternalStream::get_channel_count() const {
return player->sp_get_channel_count();
}
void SpatialStreamPlayer::InternalStream::set_mix_rate(int p_rate){
return player->sp_set_mix_rate(p_rate);
}
bool SpatialStreamPlayer::InternalStream::mix(int32_t *p_buffer,int p_frames){
return player->sp_mix(p_buffer,p_frames);
}
void SpatialStreamPlayer::InternalStream::update(){
player->sp_update();
}
int SpatialStreamPlayer::sp_get_channel_count() const {
return playback->get_channels();
}
void SpatialStreamPlayer::sp_set_mix_rate(int p_rate){
server_mix_rate=p_rate;
}
bool SpatialStreamPlayer::sp_mix(int32_t *p_buffer,int p_frames) {
if (resampler.is_ready()) {
return resampler.mix(p_buffer,p_frames);
}
return false;
}
void SpatialStreamPlayer::sp_update() {
_THREAD_SAFE_METHOD_
if (!paused && resampler.is_ready() && playback.is_valid()) {
if (!playback->is_playing()) {
//stream depleted data, but there's still audio in the ringbuffer
//check that all this audio has been flushed before stopping the stream
int to_mix = resampler.get_total() - resampler.get_todo();
if (to_mix==0) {
stop();
return;
}
return;
}
int todo =resampler.get_todo();
int wrote = playback->mix(resampler.get_write_buffer(),todo);
resampler.write(wrote);
}
}
void SpatialStreamPlayer::_notification(int p_what) { void SpatialStreamPlayer::_notification(int p_what) {
switch(p_what) { switch(p_what) {
case NOTIFICATION_ENTER_WORLD: { case NOTIFICATION_ENTER_TREE: {
// set_idle_process(false); //don't annoy //set_idle_process(false); //don't annoy
if (stream.is_valid() && autoplay && !get_tree()->is_editor_hint())
play();
} break; } break;
case NOTIFICATION_PROCESS: { case NOTIFICATION_EXIT_TREE: {
// if (!stream.is_null())
// stream->update();
} break;
case NOTIFICATION_EXIT_WORLD: {
stop(); //wathever it may be doing, stop stop(); //wathever it may be doing, stop
} break; } break;
@ -58,12 +116,20 @@ void SpatialStreamPlayer::set_stream(const Ref<AudioStream> &p_stream) {
stop(); stop();
stream=p_stream; stream=p_stream;
if (!stream.is_null()) { if (!stream.is_null()) {
playback=stream->instance_playback();
stream->set_loop(loops); playback->set_loop(loops);
playback->set_loop_restart_time(loop_point);
AudioServer::get_singleton()->lock();
resampler.setup(playback->get_channels(),playback->get_mix_rate(),server_mix_rate,buffering_ms,playback->get_minimum_buffer_size());
AudioServer::get_singleton()->unlock();
} else {
AudioServer::get_singleton()->lock();
resampler.clear();
playback.unref();
AudioServer::get_singleton()->unlock();
} }
} }
Ref<AudioStream> SpatialStreamPlayer::get_stream() const { Ref<AudioStream> SpatialStreamPlayer::get_stream() const {
@ -72,18 +138,25 @@ Ref<AudioStream> SpatialStreamPlayer::get_stream() const {
} }
void SpatialStreamPlayer::play() { void SpatialStreamPlayer::play(float p_from_offset) {
if (!is_inside_tree()) ERR_FAIL_COND(!is_inside_tree());
if (playback.is_null())
return; return;
if (stream.is_null()) if (playback->is_playing())
return;
if (stream->is_playing())
stop(); stop();
stream->play();
SpatialSoundServer::get_singleton()->source_set_audio_stream(get_source_rid(),stream->get_audio_stream()); _THREAD_SAFE_METHOD_
//if (stream->get_update_mode()!=AudioStream::UPDATE_NONE) playback->play(p_from_offset);
// set_idle_process(true); //feed the ringbuffer as long as no update callback is going on
sp_update();
SpatialSoundServer::get_singleton()->source_set_audio_stream(get_source_rid(),&internal_stream);
// AudioServer::get_singleton()->stream_set_active(stream_rid,true);
// AudioServer::get_singleton()->stream_set_volume_scale(stream_rid,volume);
// if (stream->get_update_mode()!=AudioStream::UPDATE_NONE)
// set_idle_process(true);
} }
@ -91,28 +164,30 @@ void SpatialStreamPlayer::stop() {
if (!is_inside_tree()) if (!is_inside_tree())
return; return;
if (stream.is_null()) if (playback.is_null())
return; return;
_THREAD_SAFE_METHOD_
//AudioServer::get_singleton()->stream_set_active(stream_rid,false);
SpatialSoundServer::get_singleton()->source_set_audio_stream(get_source_rid(),NULL); SpatialSoundServer::get_singleton()->source_set_audio_stream(get_source_rid(),NULL);
stream->stop(); playback->stop();
//set_idle_process(false); //set_idle_process(false);
} }
bool SpatialStreamPlayer::is_playing() const { bool SpatialStreamPlayer::is_playing() const {
if (stream.is_null()) if (playback.is_null())
return false; return false;
return stream->is_playing(); return playback->is_playing();
} }
void SpatialStreamPlayer::set_loop(bool p_enable) { void SpatialStreamPlayer::set_loop(bool p_enable) {
loops=p_enable; loops=p_enable;
if (stream.is_null()) if (playback.is_null())
return; return;
stream->set_loop(loops); playback->set_loop(loops);
} }
bool SpatialStreamPlayer::has_loop() const { bool SpatialStreamPlayer::has_loop() const {
@ -120,6 +195,46 @@ bool SpatialStreamPlayer::has_loop() const {
return loops; return loops;
} }
void SpatialStreamPlayer::set_volume(float p_vol) {
volume=p_vol;
if (stream_rid.is_valid())
AudioServer::get_singleton()->stream_set_volume_scale(stream_rid,volume);
}
float SpatialStreamPlayer::get_volume() const {
return volume;
}
void SpatialStreamPlayer::set_loop_restart_time(float p_secs) {
loop_point=p_secs;
if (playback.is_valid())
playback->set_loop_restart_time(p_secs);
}
float SpatialStreamPlayer::get_loop_restart_time() const {
return loop_point;
}
void SpatialStreamPlayer::set_volume_db(float p_db) {
if (p_db<-79)
set_volume(0);
else
set_volume(Math::db2linear(p_db));
}
float SpatialStreamPlayer::get_volume_db() const {
if (volume==0)
return -80;
else
return Math::linear2db(volume);
}
String SpatialStreamPlayer::get_stream_name() const { String SpatialStreamPlayer::get_stream_name() const {
@ -132,27 +247,85 @@ String SpatialStreamPlayer::get_stream_name() const {
int SpatialStreamPlayer::get_loop_count() const { int SpatialStreamPlayer::get_loop_count() const {
if (stream.is_null()) if (playback.is_null())
return 0; return 0;
return stream->get_loop_count(); return playback->get_loop_count();
} }
float SpatialStreamPlayer::get_pos() const { float SpatialStreamPlayer::get_pos() const {
if (stream.is_null()) if (playback.is_null())
return 0; return 0;
return stream->get_pos(); return playback->get_pos();
} }
float SpatialStreamPlayer::get_length() const {
if (playback.is_null())
return 0;
return playback->get_length();
}
void SpatialStreamPlayer::seek_pos(float p_time) { void SpatialStreamPlayer::seek_pos(float p_time) {
if (stream.is_null()) if (playback.is_null())
return; return;
return stream->seek_pos(p_time); return playback->seek_pos(p_time);
} }
void SpatialStreamPlayer::set_autoplay(bool p_enable) {
autoplay=p_enable;
}
bool SpatialStreamPlayer::has_autoplay() const {
return autoplay;
}
void SpatialStreamPlayer::set_paused(bool p_paused) {
paused=p_paused;
//if (stream.is_valid())
// stream->set_paused(p_paused);
}
bool SpatialStreamPlayer::is_paused() const {
return paused;
}
void SpatialStreamPlayer::_set_play(bool p_play) {
_play=p_play;
if (is_inside_tree()) {
if(_play)
play();
else
stop();
}
}
bool SpatialStreamPlayer::_get_play() const{
return _play;
}
void SpatialStreamPlayer::set_buffering_msec(int p_msec) {
buffering_ms=p_msec;
}
int SpatialStreamPlayer::get_buffering_msec() const{
return buffering_ms;
}
void SpatialStreamPlayer::_bind_methods() { void SpatialStreamPlayer::_bind_methods() {
ObjectTypeDB::bind_method(_MD("set_stream","stream:Stream"),&SpatialStreamPlayer::set_stream); ObjectTypeDB::bind_method(_MD("set_stream","stream:Stream"),&SpatialStreamPlayer::set_stream);
@ -163,28 +336,67 @@ void SpatialStreamPlayer::_bind_methods() {
ObjectTypeDB::bind_method(_MD("is_playing"),&SpatialStreamPlayer::is_playing); ObjectTypeDB::bind_method(_MD("is_playing"),&SpatialStreamPlayer::is_playing);
ObjectTypeDB::bind_method(_MD("set_paused","paused"),&SpatialStreamPlayer::set_paused);
ObjectTypeDB::bind_method(_MD("is_paused"),&SpatialStreamPlayer::is_paused);
ObjectTypeDB::bind_method(_MD("set_loop","enabled"),&SpatialStreamPlayer::set_loop); ObjectTypeDB::bind_method(_MD("set_loop","enabled"),&SpatialStreamPlayer::set_loop);
ObjectTypeDB::bind_method(_MD("has_loop"),&SpatialStreamPlayer::has_loop); ObjectTypeDB::bind_method(_MD("has_loop"),&SpatialStreamPlayer::has_loop);
ObjectTypeDB::bind_method(_MD("set_volume","volume"),&SpatialStreamPlayer::set_volume);
ObjectTypeDB::bind_method(_MD("get_volume"),&SpatialStreamPlayer::get_volume);
ObjectTypeDB::bind_method(_MD("set_volume_db","db"),&SpatialStreamPlayer::set_volume_db);
ObjectTypeDB::bind_method(_MD("get_volume_db"),&SpatialStreamPlayer::get_volume_db);
ObjectTypeDB::bind_method(_MD("set_buffering_msec","msec"),&SpatialStreamPlayer::set_buffering_msec);
ObjectTypeDB::bind_method(_MD("get_buffering_msec"),&SpatialStreamPlayer::get_buffering_msec);
ObjectTypeDB::bind_method(_MD("set_loop_restart_time","secs"),&SpatialStreamPlayer::set_loop_restart_time);
ObjectTypeDB::bind_method(_MD("get_loop_restart_time"),&SpatialStreamPlayer::get_loop_restart_time);
ObjectTypeDB::bind_method(_MD("get_stream_name"),&SpatialStreamPlayer::get_stream_name); ObjectTypeDB::bind_method(_MD("get_stream_name"),&SpatialStreamPlayer::get_stream_name);
ObjectTypeDB::bind_method(_MD("get_loop_count"),&SpatialStreamPlayer::get_loop_count); ObjectTypeDB::bind_method(_MD("get_loop_count"),&SpatialStreamPlayer::get_loop_count);
ObjectTypeDB::bind_method(_MD("get_pos"),&SpatialStreamPlayer::get_pos); ObjectTypeDB::bind_method(_MD("get_pos"),&SpatialStreamPlayer::get_pos);
ObjectTypeDB::bind_method(_MD("seek_pos","time"),&SpatialStreamPlayer::seek_pos); ObjectTypeDB::bind_method(_MD("seek_pos","time"),&SpatialStreamPlayer::seek_pos);
ADD_PROPERTY( PropertyInfo(Variant::OBJECT, "stream/stream", PROPERTY_HINT_RESOURCE_TYPE,"AudioStream"), _SCS("set_stream"),_SCS("get_stream") ); ObjectTypeDB::bind_method(_MD("set_autoplay","enabled"),&SpatialStreamPlayer::set_autoplay);
ADD_PROPERTY( PropertyInfo(Variant::BOOL, "stream/loop"), _SCS("set_loop"),_SCS("has_loop") ); ObjectTypeDB::bind_method(_MD("has_autoplay"),&SpatialStreamPlayer::has_autoplay);
ObjectTypeDB::bind_method(_MD("get_length"),&SpatialStreamPlayer::get_length);
ObjectTypeDB::bind_method(_MD("_set_play","play"),&SpatialStreamPlayer::_set_play);
ObjectTypeDB::bind_method(_MD("_get_play"),&SpatialStreamPlayer::_get_play);
ADD_PROPERTY( PropertyInfo(Variant::OBJECT, "stream/stream", PROPERTY_HINT_RESOURCE_TYPE,"AudioStream"), _SCS("set_stream"), _SCS("get_stream") );
ADD_PROPERTY( PropertyInfo(Variant::BOOL, "stream/play"), _SCS("_set_play"), _SCS("_get_play") );
ADD_PROPERTY( PropertyInfo(Variant::BOOL, "stream/loop"), _SCS("set_loop"), _SCS("has_loop") );
ADD_PROPERTY( PropertyInfo(Variant::REAL, "stream/volume_db", PROPERTY_HINT_RANGE,"-80,24,0.01"), _SCS("set_volume_db"), _SCS("get_volume_db") );
ADD_PROPERTY( PropertyInfo(Variant::BOOL, "stream/autoplay"), _SCS("set_autoplay"), _SCS("has_autoplay") );
ADD_PROPERTY( PropertyInfo(Variant::BOOL, "stream/paused"), _SCS("set_paused"), _SCS("is_paused") );
ADD_PROPERTY( PropertyInfo(Variant::INT, "stream/loop_restart_time"), _SCS("set_loop_restart_time"), _SCS("get_loop_restart_time") );
ADD_PROPERTY( PropertyInfo(Variant::INT, "stream/buffering_ms"), _SCS("set_buffering_msec"), _SCS("get_buffering_msec") );
} }
SpatialStreamPlayer::SpatialStreamPlayer() { SpatialStreamPlayer::SpatialStreamPlayer() {
volume=1;
loops=false; loops=false;
paused=false;
autoplay=false;
_play=false;
server_mix_rate=1;
internal_stream.player=this;
stream_rid=AudioServer::get_singleton()->audio_stream_create(&internal_stream);
buffering_ms=500;
loop_point=0;
} }
SpatialStreamPlayer::~SpatialStreamPlayer() { SpatialStreamPlayer::~SpatialStreamPlayer() {
AudioServer::get_singleton()->free(stream_rid);
resampler.clear();
} }

View File

@ -31,16 +31,48 @@
#include "scene/resources/audio_stream.h" #include "scene/resources/audio_stream.h"
#include "scene/3d/spatial_player.h" #include "scene/3d/spatial_player.h"
#include "servers/audio/audio_rb_resampler.h"
class SpatialStreamPlayer : public SpatialPlayer { class SpatialStreamPlayer : public SpatialPlayer {
OBJ_TYPE(SpatialStreamPlayer,SpatialPlayer); OBJ_TYPE(SpatialStreamPlayer,SpatialPlayer);
Ref<AudioStream> stream; _THREAD_SAFE_CLASS_
bool loops;
protected:
struct InternalStream : public AudioServer::AudioStream {
SpatialStreamPlayer *player;
virtual int get_channel_count() const;
virtual void set_mix_rate(int p_rate); //notify the stream of the mix rate
virtual bool mix(int32_t *p_buffer,int p_frames);
virtual void update();
};
InternalStream internal_stream;
Ref<AudioStreamPlayback> playback;
Ref<AudioStream> stream;
int sp_get_channel_count() const;
void sp_set_mix_rate(int p_rate); //notify the stream of the mix rate
bool sp_mix(int32_t *p_buffer,int p_frames);
void sp_update();
int server_mix_rate;
RID stream_rid;
bool paused;
bool autoplay;
bool loops;
float volume;
float loop_point;
int buffering_ms;
AudioRBResampler resampler;
bool _play;
void _set_play(bool p_play);
bool _get_play() const;
protected:
void _notification(int p_what); void _notification(int p_what);
static void _bind_methods(); static void _bind_methods();
@ -49,21 +81,37 @@ public:
void set_stream(const Ref<AudioStream> &p_stream); void set_stream(const Ref<AudioStream> &p_stream);
Ref<AudioStream> get_stream() const; Ref<AudioStream> get_stream() const;
void play(); void play(float p_from_offset=0);
void stop(); void stop();
bool is_playing() const; bool is_playing() const;
void set_paused(bool p_paused);
bool is_paused() const;
void set_loop(bool p_enable); void set_loop(bool p_enable);
bool has_loop() const; bool has_loop() const;
void set_volume(float p_vol);
float get_volume() const;
void set_loop_restart_time(float p_secs);
float get_loop_restart_time() const;
void set_volume_db(float p_db);
float get_volume_db() const;
String get_stream_name() const; String get_stream_name() const;
int get_loop_count() const;
int get_loop_count() const;
float get_pos() const; float get_pos() const;
void seek_pos(float p_time); void seek_pos(float p_time);
float get_length() const;
void set_autoplay(bool p_vol);
bool has_autoplay() const;
void set_buffering_msec(int p_msec);
int get_buffering_msec() const;
SpatialStreamPlayer(); SpatialStreamPlayer();
~SpatialStreamPlayer(); ~SpatialStreamPlayer();

View File

@ -28,6 +28,67 @@
/*************************************************************************/ /*************************************************************************/
#include "stream_player.h" #include "stream_player.h"
int StreamPlayer::InternalStream::get_channel_count() const {
return player->sp_get_channel_count();
}
void StreamPlayer::InternalStream::set_mix_rate(int p_rate){
return player->sp_set_mix_rate(p_rate);
}
bool StreamPlayer::InternalStream::mix(int32_t *p_buffer,int p_frames){
return player->sp_mix(p_buffer,p_frames);
}
void StreamPlayer::InternalStream::update(){
player->sp_update();
}
int StreamPlayer::sp_get_channel_count() const {
return playback->get_channels();
}
void StreamPlayer::sp_set_mix_rate(int p_rate){
server_mix_rate=p_rate;
}
bool StreamPlayer::sp_mix(int32_t *p_buffer,int p_frames) {
if (resampler.is_ready()) {
return resampler.mix(p_buffer,p_frames);
}
return false;
}
void StreamPlayer::sp_update() {
_THREAD_SAFE_METHOD_
if (!paused && resampler.is_ready() && playback.is_valid()) {
if (!playback->is_playing()) {
//stream depleted data, but there's still audio in the ringbuffer
//check that all this audio has been flushed before stopping the stream
int to_mix = resampler.get_total() - resampler.get_todo();
if (to_mix==0) {
stop();
return;
}
return;
}
int todo =resampler.get_todo();
int wrote = playback->mix(resampler.get_write_buffer(),todo);
resampler.write(wrote);
}
}
void StreamPlayer::_notification(int p_what) { void StreamPlayer::_notification(int p_what) {
@ -52,19 +113,21 @@ void StreamPlayer::set_stream(const Ref<AudioStream> &p_stream) {
stop(); stop();
if (stream_rid.is_valid())
AudioServer::get_singleton()->free(stream_rid);
stream_rid=RID();
stream=p_stream; stream=p_stream;
if (!stream.is_null()) { if (!stream.is_null()) {
playback=stream->instance_playback();
stream->set_loop(loops); playback->set_loop(loops);
stream->set_paused(paused); playback->set_loop_restart_time(loop_point);
stream_rid=AudioServer::get_singleton()->audio_stream_create(stream->get_audio_stream()); AudioServer::get_singleton()->lock();
resampler.setup(playback->get_channels(),playback->get_mix_rate(),server_mix_rate,buffering_ms,playback->get_minimum_buffer_size());
AudioServer::get_singleton()->unlock();
} else {
AudioServer::get_singleton()->lock();
resampler.clear();
playback.unref();
AudioServer::get_singleton()->unlock();
} }
} }
Ref<AudioStream> StreamPlayer::get_stream() const { Ref<AudioStream> StreamPlayer::get_stream() const {
@ -73,15 +136,18 @@ Ref<AudioStream> StreamPlayer::get_stream() const {
} }
void StreamPlayer::play() { void StreamPlayer::play(float p_from_offset) {
ERR_FAIL_COND(!is_inside_tree()); ERR_FAIL_COND(!is_inside_tree());
if (stream.is_null()) if (playback.is_null())
return; return;
if (stream->is_playing()) if (playback->is_playing())
stop(); stop();
stream->play(); _THREAD_SAFE_METHOD_
playback->play(p_from_offset);
//feed the ringbuffer as long as no update callback is going on
sp_update();
AudioServer::get_singleton()->stream_set_active(stream_rid,true); AudioServer::get_singleton()->stream_set_active(stream_rid,true);
AudioServer::get_singleton()->stream_set_volume_scale(stream_rid,volume); AudioServer::get_singleton()->stream_set_volume_scale(stream_rid,volume);
// if (stream->get_update_mode()!=AudioStream::UPDATE_NONE) // if (stream->get_update_mode()!=AudioStream::UPDATE_NONE)
@ -93,28 +159,29 @@ void StreamPlayer::stop() {
if (!is_inside_tree()) if (!is_inside_tree())
return; return;
if (stream.is_null()) if (playback.is_null())
return; return;
_THREAD_SAFE_METHOD_
AudioServer::get_singleton()->stream_set_active(stream_rid,false); AudioServer::get_singleton()->stream_set_active(stream_rid,false);
stream->stop(); playback->stop();
//set_idle_process(false); //set_idle_process(false);
} }
bool StreamPlayer::is_playing() const { bool StreamPlayer::is_playing() const {
if (stream.is_null()) if (playback.is_null())
return false; return false;
return stream->is_playing(); return playback->is_playing();
} }
void StreamPlayer::set_loop(bool p_enable) { void StreamPlayer::set_loop(bool p_enable) {
loops=p_enable; loops=p_enable;
if (stream.is_null()) if (playback.is_null())
return; return;
stream->set_loop(loops); playback->set_loop(loops);
} }
bool StreamPlayer::has_loop() const { bool StreamPlayer::has_loop() const {
@ -134,6 +201,19 @@ float StreamPlayer::get_volume() const {
return volume; return volume;
} }
void StreamPlayer::set_loop_restart_time(float p_secs) {
loop_point=p_secs;
if (playback.is_valid())
playback->set_loop_restart_time(p_secs);
}
float StreamPlayer::get_loop_restart_time() const {
return loop_point;
}
void StreamPlayer::set_volume_db(float p_db) { void StreamPlayer::set_volume_db(float p_db) {
if (p_db<-79) if (p_db<-79)
@ -161,31 +241,31 @@ String StreamPlayer::get_stream_name() const {
int StreamPlayer::get_loop_count() const { int StreamPlayer::get_loop_count() const {
if (stream.is_null()) if (playback.is_null())
return 0; return 0;
return stream->get_loop_count(); return playback->get_loop_count();
} }
float StreamPlayer::get_pos() const { float StreamPlayer::get_pos() const {
if (stream.is_null()) if (playback.is_null())
return 0; return 0;
return stream->get_pos(); return playback->get_pos();
} }
float StreamPlayer::get_length() const { float StreamPlayer::get_length() const {
if (stream.is_null()) if (playback.is_null())
return 0; return 0;
return stream->get_length(); return playback->get_length();
} }
void StreamPlayer::seek_pos(float p_time) { void StreamPlayer::seek_pos(float p_time) {
if (stream.is_null()) if (playback.is_null())
return; return;
return stream->seek_pos(p_time); return playback->seek_pos(p_time);
} }
@ -202,8 +282,8 @@ bool StreamPlayer::has_autoplay() const {
void StreamPlayer::set_paused(bool p_paused) { void StreamPlayer::set_paused(bool p_paused) {
paused=p_paused; paused=p_paused;
if (stream.is_valid()) //if (stream.is_valid())
stream->set_paused(p_paused); // stream->set_paused(p_paused);
} }
bool StreamPlayer::is_paused() const { bool StreamPlayer::is_paused() const {
@ -228,6 +308,17 @@ bool StreamPlayer::_get_play() const{
return _play; return _play;
} }
void StreamPlayer::set_buffering_msec(int p_msec) {
buffering_ms=p_msec;
}
int StreamPlayer::get_buffering_msec() const{
return buffering_ms;
}
void StreamPlayer::_bind_methods() { void StreamPlayer::_bind_methods() {
@ -251,6 +342,12 @@ void StreamPlayer::_bind_methods() {
ObjectTypeDB::bind_method(_MD("set_volume_db","db"),&StreamPlayer::set_volume_db); ObjectTypeDB::bind_method(_MD("set_volume_db","db"),&StreamPlayer::set_volume_db);
ObjectTypeDB::bind_method(_MD("get_volume_db"),&StreamPlayer::get_volume_db); ObjectTypeDB::bind_method(_MD("get_volume_db"),&StreamPlayer::get_volume_db);
ObjectTypeDB::bind_method(_MD("set_buffering_msec","msec"),&StreamPlayer::set_buffering_msec);
ObjectTypeDB::bind_method(_MD("get_buffering_msec"),&StreamPlayer::get_buffering_msec);
ObjectTypeDB::bind_method(_MD("set_loop_restart_time","secs"),&StreamPlayer::set_loop_restart_time);
ObjectTypeDB::bind_method(_MD("get_loop_restart_time"),&StreamPlayer::get_loop_restart_time);
ObjectTypeDB::bind_method(_MD("get_stream_name"),&StreamPlayer::get_stream_name); ObjectTypeDB::bind_method(_MD("get_stream_name"),&StreamPlayer::get_stream_name);
ObjectTypeDB::bind_method(_MD("get_loop_count"),&StreamPlayer::get_loop_count); ObjectTypeDB::bind_method(_MD("get_loop_count"),&StreamPlayer::get_loop_count);
@ -271,6 +368,8 @@ void StreamPlayer::_bind_methods() {
ADD_PROPERTY( PropertyInfo(Variant::REAL, "stream/volume_db", PROPERTY_HINT_RANGE,"-80,24,0.01"), _SCS("set_volume_db"), _SCS("get_volume_db") ); ADD_PROPERTY( PropertyInfo(Variant::REAL, "stream/volume_db", PROPERTY_HINT_RANGE,"-80,24,0.01"), _SCS("set_volume_db"), _SCS("get_volume_db") );
ADD_PROPERTY( PropertyInfo(Variant::BOOL, "stream/autoplay"), _SCS("set_autoplay"), _SCS("has_autoplay") ); ADD_PROPERTY( PropertyInfo(Variant::BOOL, "stream/autoplay"), _SCS("set_autoplay"), _SCS("has_autoplay") );
ADD_PROPERTY( PropertyInfo(Variant::BOOL, "stream/paused"), _SCS("set_paused"), _SCS("is_paused") ); ADD_PROPERTY( PropertyInfo(Variant::BOOL, "stream/paused"), _SCS("set_paused"), _SCS("is_paused") );
ADD_PROPERTY( PropertyInfo(Variant::INT, "stream/loop_restart_time"), _SCS("set_loop_restart_time"), _SCS("get_loop_restart_time") );
ADD_PROPERTY( PropertyInfo(Variant::INT, "stream/buffering_ms"), _SCS("set_buffering_msec"), _SCS("get_buffering_msec") );
} }
@ -281,10 +380,17 @@ StreamPlayer::StreamPlayer() {
paused=false; paused=false;
autoplay=false; autoplay=false;
_play=false; _play=false;
server_mix_rate=1;
internal_stream.player=this;
stream_rid=AudioServer::get_singleton()->audio_stream_create(&internal_stream);
buffering_ms=500;
loop_point=0;
} }
StreamPlayer::~StreamPlayer() { StreamPlayer::~StreamPlayer() {
if (stream_rid.is_valid()) AudioServer::get_singleton()->free(stream_rid);
AudioServer::get_singleton()->free(stream_rid); resampler.clear();
} }

View File

@ -31,17 +31,43 @@
#include "scene/resources/audio_stream.h" #include "scene/resources/audio_stream.h"
#include "scene/main/node.h" #include "scene/main/node.h"
#include "servers/audio/audio_rb_resampler.h"
class StreamPlayer : public Node { class StreamPlayer : public Node {
OBJ_TYPE(StreamPlayer,Node); OBJ_TYPE(StreamPlayer,Node);
_THREAD_SAFE_CLASS_
struct InternalStream : public AudioServer::AudioStream {
StreamPlayer *player;
virtual int get_channel_count() const;
virtual void set_mix_rate(int p_rate); //notify the stream of the mix rate
virtual bool mix(int32_t *p_buffer,int p_frames);
virtual void update();
};
InternalStream internal_stream;
Ref<AudioStreamPlayback> playback;
Ref<AudioStream> stream; Ref<AudioStream> stream;
int sp_get_channel_count() const;
void sp_set_mix_rate(int p_rate); //notify the stream of the mix rate
bool sp_mix(int32_t *p_buffer,int p_frames);
void sp_update();
int server_mix_rate;
RID stream_rid; RID stream_rid;
bool paused; bool paused;
bool autoplay; bool autoplay;
bool loops; bool loops;
float volume; float volume;
float loop_point;
int buffering_ms;
AudioRBResampler resampler;
bool _play; bool _play;
void _set_play(bool p_play); void _set_play(bool p_play);
@ -55,7 +81,7 @@ public:
void set_stream(const Ref<AudioStream> &p_stream); void set_stream(const Ref<AudioStream> &p_stream);
Ref<AudioStream> get_stream() const; Ref<AudioStream> get_stream() const;
void play(); void play(float p_from_offset=0);
void stop(); void stop();
bool is_playing() const; bool is_playing() const;
@ -68,6 +94,9 @@ public:
void set_volume(float p_vol); void set_volume(float p_vol);
float get_volume() const; float get_volume() const;
void set_loop_restart_time(float p_secs);
float get_loop_restart_time() const;
void set_volume_db(float p_db); void set_volume_db(float p_db);
float get_volume_db() const; float get_volume_db() const;
@ -81,6 +110,8 @@ public:
void set_autoplay(bool p_vol); void set_autoplay(bool p_vol);
bool has_autoplay() const; bool has_autoplay() const;
void set_buffering_msec(int p_msec);
int get_buffering_msec() const;
StreamPlayer(); StreamPlayer();
~StreamPlayer(); ~StreamPlayer();

View File

@ -578,7 +578,8 @@ void register_scene_types() {
ObjectTypeDB::register_type<Sample>(); ObjectTypeDB::register_type<Sample>();
ObjectTypeDB::register_type<SampleLibrary>(); ObjectTypeDB::register_type<SampleLibrary>();
ObjectTypeDB::register_virtual_type<AudioStream>(); ObjectTypeDB::register_virtual_type<AudioStream>();
ObjectTypeDB::register_type<AudioStreamGibberish>(); ObjectTypeDB::register_virtual_type<AudioStreamPlayback>();
// ObjectTypeDB::register_type<AudioStreamGibberish>();
ObjectTypeDB::register_virtual_type<VideoStream>(); ObjectTypeDB::register_virtual_type<VideoStream>();
OS::get_singleton()->yield(); //may take time to init OS::get_singleton()->yield(); //may take time to init

View File

@ -28,76 +28,34 @@
/*************************************************************************/ /*************************************************************************/
#include "audio_stream.h" #include "audio_stream.h"
//////////////////////////////
int AudioStream::InternalAudioStream::get_channel_count() const { void AudioStreamPlayback::_bind_methods() {
return owner->get_channel_count(); ObjectTypeDB::bind_method(_MD("play","from_pos_sec"),&AudioStreamPlayback::play,DEFVAL(0));
ObjectTypeDB::bind_method(_MD("stop"),&AudioStreamPlayback::stop);
ObjectTypeDB::bind_method(_MD("is_playing"),&AudioStreamPlayback::is_playing);
} ObjectTypeDB::bind_method(_MD("set_loop","enabled"),&AudioStreamPlayback::set_loop);
ObjectTypeDB::bind_method(_MD("has_loop"),&AudioStreamPlayback::has_loop);
void AudioStream::InternalAudioStream::set_mix_rate(int p_rate) { ObjectTypeDB::bind_method(_MD("get_loop_count"),&AudioStreamPlayback::get_loop_count);
owner->_mix_rate=p_rate; ObjectTypeDB::bind_method(_MD("seek_pos","pos"),&AudioStreamPlayback::seek_pos);
} ObjectTypeDB::bind_method(_MD("get_pos"),&AudioStreamPlayback::get_pos);
bool AudioStream::InternalAudioStream::mix(int32_t *p_buffer,int p_frames) { ObjectTypeDB::bind_method(_MD("get_length"),&AudioStreamPlayback::get_length);
ObjectTypeDB::bind_method(_MD("get_channels"),&AudioStreamPlayback::get_channels);
ObjectTypeDB::bind_method(_MD("get_mix_rate"),&AudioStreamPlayback::get_mix_rate);
ObjectTypeDB::bind_method(_MD("get_minimum_buffer_size"),&AudioStreamPlayback::get_minimum_buffer_size);
return owner->mix(p_buffer,p_frames);
}
bool AudioStream::InternalAudioStream::can_update_mt() const {
return owner->get_update_mode()==UPDATE_THREAD;
}
void AudioStream::InternalAudioStream::update() {
owner->update();
}
AudioServer::AudioStream *AudioStream::get_audio_stream() {
return internal_audio_stream;
} }
void AudioStream::_bind_methods() { void AudioStream::_bind_methods() {
ObjectTypeDB::bind_method(_MD("play"),&AudioStream::play);
ObjectTypeDB::bind_method(_MD("stop"),&AudioStream::stop);
ObjectTypeDB::bind_method(_MD("is_playing"),&AudioStream::is_playing);
ObjectTypeDB::bind_method(_MD("set_loop","enabled"),&AudioStream::set_loop);
ObjectTypeDB::bind_method(_MD("has_loop"),&AudioStream::has_loop);
ObjectTypeDB::bind_method(_MD("get_stream_name"),&AudioStream::get_stream_name);
ObjectTypeDB::bind_method(_MD("get_loop_count"),&AudioStream::get_loop_count);
ObjectTypeDB::bind_method(_MD("seek_pos","pos"),&AudioStream::seek_pos);
ObjectTypeDB::bind_method(_MD("get_pos"),&AudioStream::get_pos);
ObjectTypeDB::bind_method(_MD("get_length"),&AudioStream::get_length);
ObjectTypeDB::bind_method(_MD("get_update_mode"),&AudioStream::get_update_mode);
ObjectTypeDB::bind_method(_MD("update"),&AudioStream::update);
BIND_CONSTANT( UPDATE_NONE );
BIND_CONSTANT( UPDATE_IDLE );
BIND_CONSTANT( UPDATE_THREAD );
} }
AudioStream::AudioStream() {
_mix_rate=44100;
internal_audio_stream = memnew( InternalAudioStream );
internal_audio_stream->owner=this;
}
AudioStream::~AudioStream() {
memdelete(internal_audio_stream);
}

View File

@ -31,72 +31,53 @@
#include "resource.h" #include "resource.h"
#include "servers/audio_server.h" #include "servers/audio_server.h"
#include "scene/resources/audio_stream.h"
class AudioStream : public Resource { class AudioStreamPlayback : public Reference {
OBJ_TYPE( AudioStream, Resource ); OBJ_TYPE( AudioStreamPlayback, Reference );
OBJ_SAVE_TYPE( AudioStream ); //children are all saved as AudioStream, so they can be exchanged
friend class InternalAudioStream;
struct InternalAudioStream : public AudioServer::AudioStream {
::AudioStream *owner;
virtual int get_channel_count() const;
virtual void set_mix_rate(int p_rate); //notify the stream of the mix rate
virtual bool mix(int32_t *p_buffer,int p_frames);
virtual bool can_update_mt() const;
virtual void update();
};
int _mix_rate;
InternalAudioStream *internal_audio_stream;
protected: protected:
_FORCE_INLINE_ int get_mix_rate() const { return _mix_rate; }
virtual int get_channel_count() const=0;
virtual bool mix(int32_t *p_buffer, int p_frames)=0;
static void _bind_methods(); static void _bind_methods();
public: public:
enum UpdateMode {
UPDATE_NONE,
UPDATE_IDLE,
UPDATE_THREAD
};
AudioServer::AudioStream *get_audio_stream(); virtual void play(float p_from_pos=0)=0;
virtual void play()=0;
virtual void stop()=0; virtual void stop()=0;
virtual bool is_playing() const=0; virtual bool is_playing() const=0;
virtual void set_paused(bool p_paused)=0;
virtual bool is_paused(bool p_paused) const=0;
virtual void set_loop(bool p_enable)=0; virtual void set_loop(bool p_enable)=0;
virtual bool has_loop() const=0; virtual bool has_loop() const=0;
virtual float get_length() const=0; virtual void set_loop_restart_time(float p_time)=0;
virtual String get_stream_name() const=0;
virtual int get_loop_count() const=0; virtual int get_loop_count() const=0;
virtual float get_pos() const=0; virtual float get_pos() const=0;
virtual void seek_pos(float p_time)=0; virtual void seek_pos(float p_time)=0;
virtual UpdateMode get_update_mode() const=0; virtual int mix(int16_t* p_bufer,int p_frames)=0;
virtual void update()=0;
virtual float get_length() const=0;
virtual String get_stream_name() const=0;
virtual int get_channels() const=0;
virtual int get_mix_rate() const=0;
virtual int get_minimum_buffer_size() const=0;
};
class AudioStream : public Resource {
OBJ_TYPE( AudioStream, Resource );
OBJ_SAVE_TYPE( AudioStream ); //children are all saved as AudioStream, so they can be exchanged
protected:
static void _bind_methods();
public:
virtual Ref<AudioStreamPlayback> instance_playback()=0;
AudioStream();
~AudioStream();
}; };
VARIANT_ENUM_CAST( AudioStream::UpdateMode );
#endif // AUDIO_STREAM_H #endif // AUDIO_STREAM_H

View File

@ -28,6 +28,9 @@
/*************************************************************************/ /*************************************************************************/
#include "audio_stream_resampled.h" #include "audio_stream_resampled.h"
#include "globals.h" #include "globals.h"
#if 0
int AudioStreamResampled::get_channel_count() const { int AudioStreamResampled::get_channel_count() const {
if (!rb) if (!rb)
@ -382,3 +385,4 @@ AudioStreamResampled::~AudioStreamResampled() {
} }
#endif

View File

@ -31,6 +31,7 @@
#include "scene/resources/audio_stream.h" #include "scene/resources/audio_stream.h"
#if 0
class AudioStreamResampled : public AudioStream { class AudioStreamResampled : public AudioStream {
OBJ_TYPE(AudioStreamResampled,AudioStream); OBJ_TYPE(AudioStreamResampled,AudioStream);
@ -160,5 +161,5 @@ public:
AudioStreamResampled(); AudioStreamResampled();
~AudioStreamResampled(); ~AudioStreamResampled();
}; };
#endif
#endif // AUDIO_STREAM_RESAMPLED_H #endif // AUDIO_STREAM_RESAMPLED_H

View File

@ -29,6 +29,8 @@
#include "gibberish_stream.h" #include "gibberish_stream.h"
#include "servers/audio_server.h" #include "servers/audio_server.h"
#if 0
int AudioStreamGibberish::get_channel_count() const { int AudioStreamGibberish::get_channel_count() const {
return 1; return 1;
@ -328,3 +330,4 @@ AudioStreamGibberish::AudioStreamGibberish() {
paused=false; paused=false;
active_voices=0; active_voices=0;
} }
#endif

View File

@ -29,7 +29,7 @@
#ifndef GIBBERISH_STREAM_H #ifndef GIBBERISH_STREAM_H
#define GIBBERISH_STREAM_H #define GIBBERISH_STREAM_H
#if 0
#include "scene/resources/audio_stream.h" #include "scene/resources/audio_stream.h"
#include "scene/resources/sample_library.h" #include "scene/resources/sample_library.h"
class AudioStreamGibberish : public AudioStream { class AudioStreamGibberish : public AudioStream {
@ -109,4 +109,6 @@ public:
AudioStreamGibberish(); AudioStreamGibberish();
}; };
#endif
#endif // GIBBERISH_STREAM_H #endif // GIBBERISH_STREAM_H

View File

@ -0,0 +1,356 @@
#include "audio_rb_resampler.h"
int AudioRBResampler::get_channel_count() const {
if (!rb)
return 0;
return channels;
}
template<int C>
uint32_t AudioRBResampler::_resample(int32_t *p_dest,int p_todo,int32_t p_increment) {
uint32_t read=offset&MIX_FRAC_MASK;
for (int i=0;i<p_todo;i++) {
offset = (offset + p_increment)&(((1<<(rb_bits+MIX_FRAC_BITS))-1));
read+=p_increment;
uint32_t pos = offset >> MIX_FRAC_BITS;
uint32_t frac = offset & MIX_FRAC_MASK;
#ifndef FAST_AUDIO
ERR_FAIL_COND_V(pos>=rb_len,0);
#endif
uint32_t pos_next = (pos+1)&rb_mask;
//printf("rb pos %i\n",pos);
// since this is a template with a known compile time value (C), conditionals go away when compiling.
if (C==1) {
int32_t v0 = rb[pos];
int32_t v0n=rb[pos_next];
#ifndef FAST_AUDIO
v0+=(v0n-v0)*(int32_t)frac >> MIX_FRAC_BITS;
#endif
v0<<=16;
p_dest[i]=v0;
}
if (C==2) {
int32_t v0 = rb[(pos<<1)+0];
int32_t v1 = rb[(pos<<1)+1];
int32_t v0n=rb[(pos_next<<1)+0];
int32_t v1n=rb[(pos_next<<1)+1];
#ifndef FAST_AUDIO
v0+=(v0n-v0)*(int32_t)frac >> MIX_FRAC_BITS;
v1+=(v1n-v1)*(int32_t)frac >> MIX_FRAC_BITS;
#endif
v0<<=16;
v1<<=16;
p_dest[(i<<1)+0]=v0;
p_dest[(i<<1)+1]=v1;
}
if (C==4) {
int32_t v0 = rb[(pos<<2)+0];
int32_t v1 = rb[(pos<<2)+1];
int32_t v2 = rb[(pos<<2)+2];
int32_t v3 = rb[(pos<<2)+3];
int32_t v0n = rb[(pos_next<<2)+0];
int32_t v1n=rb[(pos_next<<2)+1];
int32_t v2n=rb[(pos_next<<2)+2];
int32_t v3n=rb[(pos_next<<2)+3];
#ifndef FAST_AUDIO
v0+=(v0n-v0)*(int32_t)frac >> MIX_FRAC_BITS;
v1+=(v1n-v1)*(int32_t)frac >> MIX_FRAC_BITS;
v2+=(v2n-v2)*(int32_t)frac >> MIX_FRAC_BITS;
v3+=(v3n-v3)*(int32_t)frac >> MIX_FRAC_BITS;
#endif
v0<<=16;
v1<<=16;
v2<<=16;
v3<<=16;
p_dest[(i<<2)+0]=v0;
p_dest[(i<<2)+1]=v1;
p_dest[(i<<2)+2]=v2;
p_dest[(i<<2)+3]=v3;
}
if (C==6) {
int32_t v0 = rb[(pos*6)+0];
int32_t v1 = rb[(pos*6)+1];
int32_t v2 = rb[(pos*6)+2];
int32_t v3 = rb[(pos*6)+3];
int32_t v4 = rb[(pos*6)+4];
int32_t v5 = rb[(pos*6)+5];
int32_t v0n = rb[(pos_next*6)+0];
int32_t v1n=rb[(pos_next*6)+1];
int32_t v2n=rb[(pos_next*6)+2];
int32_t v3n=rb[(pos_next*6)+3];
int32_t v4n=rb[(pos_next*6)+4];
int32_t v5n=rb[(pos_next*6)+5];
#ifndef FAST_AUDIO
v0+=(v0n-v0)*(int32_t)frac >> MIX_FRAC_BITS;
v1+=(v1n-v1)*(int32_t)frac >> MIX_FRAC_BITS;
v2+=(v2n-v2)*(int32_t)frac >> MIX_FRAC_BITS;
v3+=(v3n-v3)*(int32_t)frac >> MIX_FRAC_BITS;
v4+=(v4n-v4)*(int32_t)frac >> MIX_FRAC_BITS;
v5+=(v5n-v5)*(int32_t)frac >> MIX_FRAC_BITS;
#endif
v0<<=16;
v1<<=16;
v2<<=16;
v3<<=16;
v4<<=16;
v5<<=16;
p_dest[(i*6)+0]=v0;
p_dest[(i*6)+1]=v1;
p_dest[(i*6)+2]=v2;
p_dest[(i*6)+3]=v3;
p_dest[(i*6)+4]=v4;
p_dest[(i*6)+5]=v5;
}
}
return read>>MIX_FRAC_BITS;//rb_read_pos=offset>>MIX_FRAC_BITS;
}
bool AudioRBResampler::mix(int32_t *p_dest, int p_frames) {
if (!rb)
return false;
int write_pos_cache=rb_write_pos;
int32_t increment=(src_mix_rate*MIX_FRAC_LEN)/target_mix_rate;
int rb_todo;
if (write_pos_cache==rb_read_pos) {
return false; //out of buffer
} else if (rb_read_pos<write_pos_cache) {
rb_todo=write_pos_cache-rb_read_pos; //-1?
} else {
rb_todo=(rb_len-rb_read_pos)+write_pos_cache; //-1?
}
int todo = MIN( ((int64_t(rb_todo)<<MIX_FRAC_BITS)/increment)+1, p_frames );
#if 0
if (int(src_mix_rate)==target_mix_rate) {
if (channels==6) {
for(int i=0;i<p_frames;i++) {
int from = ((rb_read_pos+i)&rb_mask)*6;
int to = i*6;
p_dest[from+0]=int32_t(rb[to+0])<<16;
p_dest[from+1]=int32_t(rb[to+1])<<16;
p_dest[from+2]=int32_t(rb[to+2])<<16;
p_dest[from+3]=int32_t(rb[to+3])<<16;
p_dest[from+4]=int32_t(rb[to+4])<<16;
p_dest[from+5]=int32_t(rb[to+5])<<16;
}
} else {
int len=p_frames*channels;
int from=rb_read_pos*channels;
int mask=0;
switch(channels) {
case 1: mask=rb_len-1; break;
case 2: mask=(rb_len*2)-1; break;
case 4: mask=(rb_len*4)-1; break;
}
for(int i=0;i<len;i++) {
p_dest[i]=int32_t(rb[(from+i)&mask])<<16;
}
}
rb_read_pos = (rb_read_pos+p_frames)&rb_mask;
} else
#endif
{
uint32_t read=0;
switch(channels) {
case 1: read=_resample<1>(p_dest,todo,increment); break;
case 2: read=_resample<2>(p_dest,todo,increment); break;
case 4: read=_resample<4>(p_dest,todo,increment); break;
case 6: read=_resample<6>(p_dest,todo,increment); break;
}
#if 1
//end of stream, fadeout
int remaining = p_frames-todo;
if (remaining && todo>0) {
//print_line("fadeout");
for(int c=0;c<channels;c++) {
for(int i=0;i<todo;i++) {
int32_t samp = p_dest[i*channels+c]>>8;
uint32_t mul = (todo-i) * 256 /todo;
//print_line("mul: "+itos(i)+" "+itos(mul));
p_dest[i*channels+c]=samp*mul;
}
}
}
#else
int remaining = p_frames-todo;
if (remaining && todo>0) {
for(int c=0;c<channels;c++) {
int32_t from = p_dest[(todo-1)*channels+c]>>8;
for(int i=0;i<remaining;i++) {
uint32_t mul = (remaining-i) * 256 /remaining;
p_dest[(todo+i)*channels+c]=from*mul;
}
}
}
#endif
//zero out what remains there to avoid glitches
for(int i=todo*channels;i<int(p_frames)*channels;i++) {
p_dest[i]=0;
}
if (read>rb_todo)
read=rb_todo;
rb_read_pos = (rb_read_pos+read)&rb_mask;
}
return true;
}
Error AudioRBResampler::setup(int p_channels,int p_src_mix_rate,int p_target_mix_rate,int p_buffer_msec,int p_minbuff_needed) {
ERR_FAIL_COND_V(p_channels!=1 && p_channels!=2 && p_channels!=4 && p_channels!=6,ERR_INVALID_PARAMETER);
//float buffering_sec = int(GLOBAL_DEF("audio/stream_buffering_ms",500))/1000.0;
int desired_rb_bits =nearest_shift(MAX((p_buffer_msec/1000.0)*p_src_mix_rate,p_minbuff_needed));
bool recreate=!rb;
if (rb && (uint32_t(desired_rb_bits)!=rb_bits || channels!=uint32_t(p_channels))) {
//recreate
memdelete_arr(rb);
memdelete_arr(read_buf);
recreate=true;
}
if (recreate) {
channels=p_channels;
rb_bits=desired_rb_bits;
rb_len=(1<<rb_bits);
rb_mask=rb_len-1;
rb = memnew_arr( int16_t, rb_len * p_channels );
read_buf = memnew_arr( int16_t, rb_len * p_channels );
}
src_mix_rate=p_src_mix_rate;
target_mix_rate=p_target_mix_rate;
offset=0;
rb_read_pos=0;
rb_write_pos=0;
//avoid maybe strange noises upon load
for (int i=0;i<(rb_len*channels);i++) {
rb[i]=0;
read_buf[i]=0;
}
return OK;
}
void AudioRBResampler::clear() {
if (!rb)
return;
//should be stopped at this point but just in case
if (rb) {
memdelete_arr(rb);
memdelete_arr(read_buf);
}
rb=NULL;
offset=0;
rb_read_pos=0;
rb_write_pos=0;
read_buf=NULL;
}
AudioRBResampler::AudioRBResampler() {
rb=NULL;
offset=0;
read_buf=NULL;
rb_read_pos=0;
rb_write_pos=0;
rb_bits=0;
rb_len=0;
rb_mask=0;
read_buff_len=0;
channels=0;
src_mix_rate=0;
target_mix_rate=0;
}
AudioRBResampler::~AudioRBResampler() {
if (rb) {
memdelete_arr(rb);
memdelete_arr(read_buf);
}
}

View File

@ -0,0 +1,133 @@
#ifndef AUDIO_RB_RESAMPLER_H
#define AUDIO_RB_RESAMPLER_H
#include "typedefs.h"
#include "os/memory.h"
struct AudioRBResampler {
uint32_t rb_bits;
uint32_t rb_len;
uint32_t rb_mask;
uint32_t read_buff_len;
uint32_t channels;
uint32_t src_mix_rate;
uint32_t target_mix_rate;
volatile int rb_read_pos;
volatile int rb_write_pos;
int32_t offset; //contains the fractional remainder of the resampler
enum {
MIX_FRAC_BITS=13,
MIX_FRAC_LEN=(1<<MIX_FRAC_BITS),
MIX_FRAC_MASK=MIX_FRAC_LEN-1,
};
int16_t *read_buf;
int16_t *rb;
template<int C>
uint32_t _resample(int32_t *p_dest,int p_todo,int32_t p_increment);
public:
_FORCE_INLINE_ void flush() {
rb_read_pos=0;
rb_write_pos=0;
}
_FORCE_INLINE_ bool is_ready() const{
return rb!=NULL;
}
_FORCE_INLINE_ int get_total() const {
return rb_len-1;
}
_FORCE_INLINE_ int get_todo() const { //return amount of frames to mix
int todo;
int read_pos_cache=rb_read_pos;
if (read_pos_cache==rb_write_pos) {
todo=rb_len-1;
} else if (read_pos_cache>rb_write_pos) {
todo=read_pos_cache-rb_write_pos-1;
} else {
todo=(rb_len-rb_write_pos)+read_pos_cache-1;
}
return todo;
}
_FORCE_INLINE_ int16_t *get_write_buffer() { return read_buf; }
_FORCE_INLINE_ void write(uint32_t p_frames) {
ERR_FAIL_COND(p_frames >= rb_len);
switch(channels) {
case 1: {
for(uint32_t i=0;i<p_frames;i++) {
rb[ rb_write_pos ] = read_buf[i];
rb_write_pos=(rb_write_pos+1)&rb_mask;
}
} break;
case 2: {
for(uint32_t i=0;i<p_frames;i++) {
rb[ (rb_write_pos<<1)+0 ] = read_buf[(i<<1)+0];
rb[ (rb_write_pos<<1)+1 ] = read_buf[(i<<1)+1];
rb_write_pos=(rb_write_pos+1)&rb_mask;
}
} break;
case 4: {
for(uint32_t i=0;i<p_frames;i++) {
rb[ (rb_write_pos<<2)+0 ] = read_buf[(i<<2)+0];
rb[ (rb_write_pos<<2)+1 ] = read_buf[(i<<2)+1];
rb[ (rb_write_pos<<2)+2 ] = read_buf[(i<<2)+2];
rb[ (rb_write_pos<<2)+3 ] = read_buf[(i<<2)+3];
rb_write_pos=(rb_write_pos+1)&rb_mask;
}
} break;
case 6: {
for(uint32_t i=0;i<p_frames;i++) {
rb[ (rb_write_pos*6)+0 ] = read_buf[(i*6)+0];
rb[ (rb_write_pos*6)+1 ] = read_buf[(i*6)+1];
rb[ (rb_write_pos*6)+2 ] = read_buf[(i*6)+2];
rb[ (rb_write_pos*6)+3 ] = read_buf[(i*6)+3];
rb[ (rb_write_pos*6)+4 ] = read_buf[(i*6)+4];
rb[ (rb_write_pos*6)+5 ] = read_buf[(i*6)+5];
rb_write_pos=(rb_write_pos+1)&rb_mask;
}
} break;
}
}
int get_channel_count() const;
Error setup(int p_channels, int p_src_mix_rate, int p_target_mix_rate, int p_buffer_msec, int p_minbuff_needed=-1);
void clear();
bool mix(int32_t *p_dest, int p_frames);
AudioRBResampler();
~AudioRBResampler();
};
#endif // AUDIO_RB_RESAMPLER_H

View File

@ -830,10 +830,14 @@ void AudioServerSW::finish() {
void AudioServerSW::_update_streams(bool p_thread) { void AudioServerSW::_update_streams(bool p_thread) {
_THREAD_SAFE_METHOD_ _THREAD_SAFE_METHOD_
for(List<Stream*>::Element *E=active_audio_streams.front();E;E=E->next()) { for(List<Stream*>::Element *E=active_audio_streams.front();E;) { //stream might be removed durnig this callback
List<Stream*>::Element *N=E->next();
if (E->get()->audio_stream && p_thread == E->get()->audio_stream->can_update_mt()) if (E->get()->audio_stream && p_thread == E->get()->audio_stream->can_update_mt())
E->get()->audio_stream->update(); E->get()->audio_stream->update();
E=N;
} }
} }

View File

@ -201,6 +201,8 @@ public:
}; };
class SpatialPlayerSpatialGizmo : public SpatialGizmoTool { class SpatialPlayerSpatialGizmo : public SpatialGizmoTool {
OBJ_TYPE(SpatialPlayerSpatialGizmo,SpatialGizmoTool); OBJ_TYPE(SpatialPlayerSpatialGizmo,SpatialGizmoTool);
@ -214,6 +216,8 @@ public:
}; };
class TestCubeSpatialGizmo : public SpatialGizmoTool { class TestCubeSpatialGizmo : public SpatialGizmoTool {
OBJ_TYPE(TestCubeSpatialGizmo,SpatialGizmoTool); OBJ_TYPE(TestCubeSpatialGizmo,SpatialGizmoTool);