|
@@ -17,6 +17,48 @@
|
|
#include "../../../sdl2/SDL/src/core/android/SDL_android.h"
|
|
#include "../../../sdl2/SDL/src/core/android/SDL_android.h"
|
|
#endif
|
|
#endif
|
|
|
|
|
|
|
|
+#include <atomic>
|
|
|
|
+
|
|
|
|
+namespace{
|
|
|
|
+
|
|
|
|
+ struct Counter;
|
|
|
|
+
|
|
|
|
+ Counter *counters;
|
|
|
|
+
|
|
|
|
+ //Yikes! We have to make a little atomic counter class!
|
|
|
|
+ //
|
|
|
|
+ struct Counter{
|
|
|
|
+
|
|
|
|
+ Counter *succ;
|
|
|
|
+ int source;
|
|
|
|
+ std::atomic<int> count=0;
|
|
|
|
+
|
|
|
|
+ Counter( int source ):source( source ){
|
|
|
|
+ succ=counters;
|
|
|
|
+ counters=this;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ ~Counter(){
|
|
|
|
+ Counter **pred=&counters;
|
|
|
|
+
|
|
|
|
+ while( Counter *c=*pred ){
|
|
|
|
+ if( c==this ){
|
|
|
|
+ *pred=succ;
|
|
|
|
+ }
|
|
|
|
+ pred=&c->succ;
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ };
|
|
|
|
+
|
|
|
|
+ Counter *getCounter( int source ){
|
|
|
|
+ for( Counter *c=counters;c;c=c->succ ){
|
|
|
|
+ if( c->source==source ) return c;
|
|
|
|
+ }
|
|
|
|
+ return 0;
|
|
|
|
+ }
|
|
|
|
+}
|
|
|
|
+
|
|
|
|
+
|
|
namespace bbMusic{
|
|
namespace bbMusic{
|
|
|
|
|
|
#if __ANDROID__
|
|
#if __ANDROID__
|
|
@@ -61,36 +103,35 @@ namespace bbMusic{
|
|
return ::fopen( path,mode );
|
|
return ::fopen( path,mode );
|
|
}
|
|
}
|
|
|
|
|
|
- bool playMusic( const char *path,int callback,int alsource ){
|
|
|
|
|
|
+ int playMusic( const char *path,int callback,int alsource ){
|
|
|
|
|
|
|
|
+ const int buffer_ms=100;
|
|
|
|
+
|
|
FILE *file=fopen( path,"rb" );
|
|
FILE *file=fopen( path,"rb" );
|
|
if( !file ) return false;
|
|
if( !file ) return false;
|
|
|
|
|
|
int error=0;
|
|
int error=0;
|
|
stb_vorbis *vorbis=stb_vorbis_open_file( file,0,&error,0 );
|
|
stb_vorbis *vorbis=stb_vorbis_open_file( file,0,&error,0 );
|
|
if( !vorbis ) return false;
|
|
if( !vorbis ) return false;
|
|
|
|
+
|
|
|
|
+ stb_vorbis_info info=stb_vorbis_get_info( vorbis );
|
|
|
|
+
|
|
|
|
+ Counter *buffersProcessed=new Counter( alsource );
|
|
|
|
|
|
std::thread thread( [=](){
|
|
std::thread thread( [=](){
|
|
|
|
|
|
ALuint source=alsource;
|
|
ALuint source=alsource;
|
|
|
|
|
|
- stb_vorbis_info info=stb_vorbis_get_info( vorbis );
|
|
|
|
-
|
|
|
|
// int length=stb_vorbis_stream_length_in_samples( vorbis );
|
|
// int length=stb_vorbis_stream_length_in_samples( vorbis );
|
|
// float duration=stb_vorbis_stream_length_in_seconds( vorbis );
|
|
// float duration=stb_vorbis_stream_length_in_seconds( vorbis );
|
|
// bb_printf( "vorbis length=%i, duration=%f, info.sample_rate=%i, info.channels=%i\n",length,duration,info.sample_rate,info.channels );
|
|
// bb_printf( "vorbis length=%i, duration=%f, info.sample_rate=%i, info.channels=%i\n",length,duration,info.sample_rate,info.channels );
|
|
|
|
|
|
ALenum format=(info.channels==2 ? AL_FORMAT_STEREO16 : AL_FORMAT_MONO16);
|
|
ALenum format=(info.channels==2 ? AL_FORMAT_STEREO16 : AL_FORMAT_MONO16);
|
|
|
|
|
|
-// int buffer_size=8192;
|
|
|
|
-// int nsamples=buffer_size / (info.channels==2 ? 4 : 2);
|
|
|
|
-// int buffer_ms=nsamples*1000/info.sample_rate;
|
|
|
|
-
|
|
|
|
- int buffer_ms=100;
|
|
|
|
int nsamples=buffer_ms*info.sample_rate/1000;
|
|
int nsamples=buffer_ms*info.sample_rate/1000;
|
|
int buffer_size=nsamples * (info.channels==2 ? 4 : 2);
|
|
int buffer_size=nsamples * (info.channels==2 ? 4 : 2);
|
|
|
|
|
|
-// bb_printf( "buffer_size=%i, buffer_ms=%i\n",buffer_size,buffer_ms );
|
|
|
|
|
|
+// bb_printf( "Samples per buffer=%i\n",nsamples );
|
|
|
|
|
|
//polling for paused occasionally fails with only 2 buffers
|
|
//polling for paused occasionally fails with only 2 buffers
|
|
|
|
|
|
@@ -101,56 +142,61 @@ namespace bbMusic{
|
|
|
|
|
|
short *vorbis_data=new short[buffer_size/2];
|
|
short *vorbis_data=new short[buffer_size/2];
|
|
|
|
|
|
|
|
+ int n=buffer_size;
|
|
|
|
+
|
|
for( int i=0;i<numbufs;++i ){
|
|
for( int i=0;i<numbufs;++i ){
|
|
- int n=stb_vorbis_get_samples_short_interleaved( vorbis,info.channels,vorbis_data,buffer_size/2 );
|
|
|
|
|
|
+
|
|
|
|
+ if( n ) n=stb_vorbis_get_samples_short_interleaved( vorbis,info.channels,vorbis_data,buffer_size/2 );
|
|
|
|
+
|
|
alBufferData( buffers[i],format,vorbis_data,buffer_size,info.sample_rate );
|
|
alBufferData( buffers[i],format,vorbis_data,buffer_size,info.sample_rate );
|
|
}
|
|
}
|
|
-
|
|
|
|
|
|
+
|
|
alSourceQueueBuffers( source,numbufs,buffers );
|
|
alSourceQueueBuffers( source,numbufs,buffers );
|
|
|
|
|
|
alSourcePlay( source );
|
|
alSourcePlay( source );
|
|
|
|
|
|
// bb_printf( "Playing music...\n" );
|
|
// bb_printf( "Playing music...\n" );
|
|
-
|
|
|
|
|
|
+
|
|
for(;;){
|
|
for(;;){
|
|
|
|
|
|
|
|
+ //decode more...
|
|
|
|
+ if( n ) n=stb_vorbis_get_samples_short_interleaved( vorbis,info.channels,vorbis_data,buffer_size/2 );
|
|
|
|
+
|
|
ALenum state;
|
|
ALenum state;
|
|
|
|
|
|
- int n=stb_vorbis_get_samples_short_interleaved( vorbis,info.channels,vorbis_data,buffer_size/2 );
|
|
|
|
- if( !n ){
|
|
|
|
- //no more data, wait for audio to stop...
|
|
|
|
- for(;;){
|
|
|
|
- alGetSourcei( source,AL_SOURCE_STATE,&state );
|
|
|
|
- if( state==AL_STOPPED ) break;
|
|
|
|
- std::this_thread::sleep_for( std::chrono::milliseconds( buffer_ms/2 ) );
|
|
|
|
- }
|
|
|
|
- break;
|
|
|
|
- }
|
|
|
|
-
|
|
|
|
for(;;){
|
|
for(;;){
|
|
|
|
|
|
alGetSourcei( source,AL_SOURCE_STATE,&state );
|
|
alGetSourcei( source,AL_SOURCE_STATE,&state );
|
|
|
|
+
|
|
if( state==AL_STOPPED ) break;
|
|
if( state==AL_STOPPED ) break;
|
|
|
|
+
|
|
|
|
+ if( state==AL_PLAYING ){
|
|
|
|
|
|
- ALint processed;
|
|
|
|
- alGetSourcei( source,AL_BUFFERS_PROCESSED,&processed );
|
|
|
|
-
|
|
|
|
-// if( processed>1 ) bb_printf( "processed=%i\n",processed );
|
|
|
|
-
|
|
|
|
- if( state==AL_PLAYING && processed ) break;
|
|
|
|
|
|
+ ALint processed;
|
|
|
|
+ alGetSourcei( source,AL_BUFFERS_PROCESSED,&processed );
|
|
|
|
|
|
|
|
+// if( processed>1 ) bb_printf( "processed=%i\n",processed );
|
|
|
|
+
|
|
|
|
+ if( processed ) break;
|
|
|
|
+ }
|
|
|
|
+
|
|
std::this_thread::sleep_for( std::chrono::milliseconds( buffer_ms/2 ) );
|
|
std::this_thread::sleep_for( std::chrono::milliseconds( buffer_ms/2 ) );
|
|
}
|
|
}
|
|
|
|
+
|
|
if( state==AL_STOPPED ){
|
|
if( state==AL_STOPPED ){
|
|
// bb_printf( "AL_STOPPED\n" );
|
|
// bb_printf( "AL_STOPPED\n" );
|
|
break;
|
|
break;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+ buffersProcessed->count+=1;
|
|
|
|
+
|
|
ALuint buffer;
|
|
ALuint buffer;
|
|
alSourceUnqueueBuffers( source,1,&buffer );
|
|
alSourceUnqueueBuffers( source,1,&buffer );
|
|
-
|
|
|
|
- alBufferData( buffer,format,vorbis_data,buffer_size,info.sample_rate );
|
|
|
|
|
|
|
|
|
|
+ if( !n ) continue;
|
|
|
|
+
|
|
|
|
+ alBufferData( buffer,format,vorbis_data,buffer_size,info.sample_rate );
|
|
|
|
+
|
|
alSourceQueueBuffers( source,1,&buffer );
|
|
alSourceQueueBuffers( source,1,&buffer );
|
|
}
|
|
}
|
|
|
|
|
|
@@ -158,7 +204,7 @@ namespace bbMusic{
|
|
|
|
|
|
alSourceStop( source );
|
|
alSourceStop( source );
|
|
|
|
|
|
- alDeleteBuffers( 2,buffers );
|
|
|
|
|
|
+ alDeleteBuffers( numbufs,buffers );
|
|
|
|
|
|
delete[] vorbis_data;
|
|
delete[] vorbis_data;
|
|
|
|
|
|
@@ -170,8 +216,19 @@ namespace bbMusic{
|
|
} );
|
|
} );
|
|
|
|
|
|
thread.detach();
|
|
thread.detach();
|
|
-
|
|
|
|
- return true;
|
|
|
|
|
|
+
|
|
|
|
+ return info.sample_rate;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ int getBuffersProcessed( int source ){
|
|
|
|
+ Counter *c=getCounter( source );
|
|
|
|
+ if( c ) return c->count;
|
|
|
|
+ return 0;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ void endMusic( int source ){
|
|
|
|
+ Counter *c=getCounter( source );
|
|
|
|
+ delete c;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|