mirror of
https://github.com/godotengine/godot.git
synced 2024-11-24 21:22:48 +00:00
Merge branch 'master' of https://github.com/okamstudio/godot
This commit is contained in:
commit
3013a83f2f
@ -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();
|
||||||
|
|
||||||
|
@ -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:
|
||||||
|
@ -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) {
|
||||||
|
@ -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);
|
||||||
|
@ -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;
|
||||||
}
|
}
|
||||||
|
@ -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, ¤t_section);
|
long ret=ov_read(&vf,(char*)p_bufer,todo*stream_channels*sizeof(int16_t), 1, 2, 1, ¤t_section);
|
||||||
#else
|
#else
|
||||||
long ret=ov_read(&vf,(char*)get_write_buffer(),todo*stream_channels*sizeof(int16_t), 0, 2, 1, ¤t_section);
|
long ret=ov_read(&vf,(char*)p_bufer,todo*stream_channels*sizeof(int16_t), 0, 2, 1, ¤t_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();
|
||||||
|
|
||||||
|
@ -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 {
|
||||||
|
@ -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 {
|
||||||
|
@ -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)
|
||||||
|
@ -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"):
|
||||||
|
@ -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();
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -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();
|
||||||
|
@ -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();
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -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();
|
||||||
|
@ -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
|
||||||
|
@ -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);
|
|
||||||
}
|
|
||||||
|
@ -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
|
||||||
|
@ -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
|
||||||
|
@ -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
|
||||||
|
@ -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
|
||||||
|
@ -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
|
||||||
|
356
servers/audio/audio_rb_resampler.cpp
Normal file
356
servers/audio/audio_rb_resampler.cpp
Normal 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);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
133
servers/audio/audio_rb_resampler.h
Normal file
133
servers/audio/audio_rb_resampler.h
Normal 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
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -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);
|
||||||
|
Loading…
Reference in New Issue
Block a user