Rearchitect colorchord using CNFA + Rawdraw modules.
This commit is contained in:
parent
e243c7200b
commit
3d922b514c
3
.gitmodules
vendored
3
.gitmodules
vendored
|
@ -4,3 +4,6 @@
|
|||
[submodule "colorchord2/rawdraw"]
|
||||
path = colorchord2/rawdraw
|
||||
url = https://github.com/cntools/rawdraw
|
||||
[submodule "colorchord2/cnfa"]
|
||||
path = colorchord2/cnfa
|
||||
url = https://github.com/cnlohr/cnfa
|
||||
|
|
|
@ -1,29 +1,26 @@
|
|||
all : colorchord
|
||||
|
||||
RAWDRAW:=DrawFunctions.o XDriver.o
|
||||
SOUND:=sound.o sound_alsa.o sound_pulse.o sound_null.o
|
||||
|
||||
OUTS := OutputVoronoi.o DisplayArray.o OutputLinear.o DisplayPie.o DisplayNetwork.o DisplayUSB2812.o DisplayDMX.o OutputProminent.o RecorderPlugin.o DisplayHIDAPI.o hidapi.o OutputCells.o DisplaySHM.o DisplayFileWrite.o
|
||||
|
||||
WINGCC:= i686-w64-mingw32-gcc
|
||||
|
||||
WINGCCFLAGS:= -g -DICACHE_FLASH_ATTR= -I../embeddedcommon -I. -O1 #-O2 -Wl,--relax -Wl,--gc-sections -ffunction-sections -fdata-sections
|
||||
WINGCCFLAGS:= -g -DICACHE_FLASH_ATTR= -I../embeddedcommon -Icnfa -Irawdraw -I. -O1 #-O2 -Wl,--relax -Wl,--gc-sections -ffunction-sections -fdata-sections
|
||||
WINLDFLAGS:=-lwinmm -lgdi32 -lws2_32 -lsetupapi
|
||||
|
||||
RAWDRAWLIBS:=-lX11 -lm -lpthread -lXinerama -lXext
|
||||
LDLIBS:=-lpthread -lasound -lm -lpulse-simple -lpulse -ludev -lrt
|
||||
|
||||
|
||||
CFLAGS:=-g -O1 -flto -Wall -ffast-math -I../embeddedcommon -I. -DICACHE_FLASH_ATTR=
|
||||
CFLAGS:=-g -O1 -flto -Wall -ffast-math -I../embeddedcommon -I. -Icnfa -Irawdraw -DICACHE_FLASH_ATTR=
|
||||
EXTRALIBS:=-lusb-1.0
|
||||
|
||||
OBJS:=os_generic.o main.o dft.o decompose.o filter.o color.o notefinder.o util.o outdrivers.o $(RAWDRAW) $(SOUND) $(OUTS) parameters.o chash.o hook.o ../embeddedcommon/DFT32.o configs.o
|
||||
OBJS:=os_generic.o main.o dft.o decompose.o filter.o color.o notefinder.o util.o outdrivers.o $(OUTS) parameters.o chash.o hook.o ../embeddedcommon/DFT32.o configs.o
|
||||
|
||||
colorchord : $(OBJS)
|
||||
gcc -o $@ $^ $(CFLAGS) $(LDLIBS) $(EXTRALIBS) $(RAWDRAWLIBS)
|
||||
|
||||
|
||||
colorchord.exe : os_generic.c main.c dft.c decompose.c filter.c color.c notefinder.c util.c outdrivers.c DrawFunctions.c parameters.c chash.c WinDriver.c sound.c sound_null.c sound_win.c OutputVoronoi.c OutputProminent.c DisplayArray.c OutputLinear.c DisplayPie.c DisplayNetwork.c hook.c RecorderPlugin.c ../embeddedcommon/DFT32.c OutputCells.c configs.c hidapi.c DisplayHIDAPI.c
|
||||
colorchord.exe : os_generic.c main.c dft.c decompose.c filter.c color.c notefinder.c util.c outdrivers.c parameters.c chash.c OutputVoronoi.c OutputProminent.c DisplayArray.c OutputLinear.c DisplayPie.c DisplayNetwork.c hook.c RecorderPlugin.c ../embeddedcommon/DFT32.c OutputCells.c configs.c hidapi.c DisplayHIDAPI.c
|
||||
$(WINGCC) $(WINGCCFLAGS) -o $@ $^ $(WINLDFLAGS)
|
||||
|
||||
|
||||
|
|
|
@ -107,7 +107,7 @@ void StartRecording( struct RecorderPlugin * rp )
|
|||
}
|
||||
|
||||
|
||||
static void RecordEvent(void * v, int samples, float * samps, int channel_ct)
|
||||
static void RecordEvent(void * v, int samples, short * samps, int channel_ct)
|
||||
{
|
||||
struct RecorderPlugin * rp = (struct RecorderPlugin*)v;
|
||||
|
||||
|
@ -115,7 +115,7 @@ static void RecordEvent(void * v, int samples, float * samps, int channel_ct)
|
|||
|
||||
if( rp->DunBoop || !rp->fPlay )
|
||||
{
|
||||
int r = fwrite( samps, channel_ct * sizeof( float ), samples, rp->fRec );
|
||||
int r = fwrite( samps, channel_ct * sizeof( short ), samples, rp->fRec );
|
||||
if( r != samples )
|
||||
{
|
||||
StopRecording( rp );
|
||||
|
@ -123,12 +123,12 @@ static void RecordEvent(void * v, int samples, float * samps, int channel_ct)
|
|||
}
|
||||
}
|
||||
|
||||
static void PlaybackEvent(void * v, int samples, float * samps, int channel_ct)
|
||||
static void PlaybackEvent(void * v, int samples, short * samps, int channel_ct)
|
||||
{
|
||||
struct RecorderPlugin * rp = (struct RecorderPlugin*)v;
|
||||
if( !rp->fPlay ) return;
|
||||
|
||||
int r = fread( samps, channel_ct * sizeof( float ), samples, rp->fPlay );
|
||||
int r = fread( samps, channel_ct * sizeof( short ), samples, rp->fPlay );
|
||||
if( r != samples )
|
||||
{
|
||||
StopRecording( rp );
|
||||
|
@ -143,7 +143,7 @@ static void PlaybackEvent(void * v, int samples, float * samps, int channel_ct)
|
|||
else
|
||||
force_white = 0;
|
||||
|
||||
int r = fwrite( samps, channel_ct * sizeof( float ), samples, rp->fRec );
|
||||
int r = fwrite( samps, channel_ct * sizeof( short ), samples, rp->fRec );
|
||||
if( r != samples )
|
||||
{
|
||||
StopRecording( rp );
|
||||
|
|
1
colorchord2/cnfa
Submodule
1
colorchord2/cnfa
Submodule
|
@ -0,0 +1 @@
|
|||
Subproject commit 22f0e58a4df57c6a6b5fa05665a6d454e597e2da
|
Binary file not shown.
|
@ -54,14 +54,14 @@ void UnhookKeyEvent( void (*KeyE)( void * v, int key, int down ), void * v )
|
|||
|
||||
struct SoundEvent
|
||||
{
|
||||
void (*SoundE)( void * v, int samples, float * samps, int channel_ct );
|
||||
void (*SoundE)( void * v, int samples, short * samps, int channel_ct );
|
||||
void * v;
|
||||
};
|
||||
|
||||
struct SoundEvent SoundEvents[2][MAX_SOUND_EVENTS];
|
||||
|
||||
|
||||
void SoundEventHappened( int samples, float * samps, int is_out, int channel_ct )
|
||||
void SoundEventHappened( int samples, short * samps, int is_out, int channel_ct )
|
||||
{
|
||||
int i;
|
||||
for( i = 0; i < MAX_SOUND_EVENTS; i++ )
|
||||
|
@ -73,7 +73,7 @@ void SoundEventHappened( int samples, float * samps, int is_out, int channel_ct
|
|||
}
|
||||
}
|
||||
|
||||
void HookSoundInEvent( void (*SoundE)( void * v, int samples, float * samps, int channel_ct ), void * v, int is_out )
|
||||
void HookSoundInEvent( void (*SoundE)( void * v, int samples, short * samps, int channel_ct ), void * v, int is_out )
|
||||
{
|
||||
int i;
|
||||
for( i = 0; i < MAX_SOUND_EVENTS; i++ )
|
||||
|
@ -87,7 +87,7 @@ void HookSoundInEvent( void (*SoundE)( void * v, int samples, float * samps, int
|
|||
}
|
||||
}
|
||||
|
||||
void UnhookSoundInEvent( void (*SoundE)( void * v, int samples, float * samps, int channel_ct ), void * v, int is_out )
|
||||
void UnhookSoundInEvent( void (*SoundE)( void * v, int samples, short * samps, int channel_ct ), void * v, int is_out )
|
||||
{
|
||||
int i;
|
||||
for( i = 0; i < MAX_SOUND_EVENTS; i++ )
|
||||
|
|
|
@ -11,9 +11,9 @@ void HookKeyEvent( void (*KeyEvent)( void * v, int key, int down ), void * v );
|
|||
void UnhookKeyEvent( void (*KeyEvent)( void * v, int key, int down ), void * v );
|
||||
|
||||
|
||||
void SoundEventHappened( int samples, float * samps, int channel_ct, int is_out );
|
||||
void HookSoundInEvent( void (*SoundE)( void * v, int samples, float * samps, int channel_ct ), void * v, int is_out );
|
||||
void UnhookSoundInEvent( void (*SoundE)( void * v, int samples, float * samps, int channel_ct ), void * v, int is_out );
|
||||
void SoundEventHappened( int samples, short * samps, int channel_ct, int is_out );
|
||||
void HookSoundInEvent( void (*SoundE)( void * v, int samples, short * samps, int channel_ct ), void * v, int is_out );
|
||||
void UnhookSoundInEvent( void (*SoundE)( void * v, int samples, short * samps, int channel_ct ), void * v, int is_out );
|
||||
|
||||
|
||||
#endif
|
||||
|
|
|
@ -1,12 +1,15 @@
|
|||
//Copyright 2015 <>< Charles Lohr under the ColorChord License.
|
||||
|
||||
#if defined(WIN32) || defined(USE_WINDOWS)
|
||||
#include <winsock2.h>
|
||||
#include <windows.h>
|
||||
#endif
|
||||
|
||||
#include <ctype.h>
|
||||
#include "color.h"
|
||||
#include <math.h>
|
||||
#include <stdio.h>
|
||||
#include "sound.h"
|
||||
#include "os_generic.h"
|
||||
#include "DrawFunctions.h"
|
||||
#include "dft.h"
|
||||
#include "filter.h"
|
||||
#include "decompose.h"
|
||||
|
@ -18,6 +21,19 @@
|
|||
#include "hook.h"
|
||||
#include "configs.h"
|
||||
|
||||
|
||||
#define CNFG_IMPLEMENTATION
|
||||
#include "CNFG.h"
|
||||
|
||||
#define CNFA_IMPLEMENTATION
|
||||
#include "CNFA.h"
|
||||
|
||||
|
||||
|
||||
//Sound driver.
|
||||
struct CNFADriver * sd;
|
||||
|
||||
|
||||
#ifdef ANDROID
|
||||
#include <unistd.h>
|
||||
#include <sys/types.h>
|
||||
|
@ -25,7 +41,6 @@
|
|||
#include <fcntl.h>
|
||||
#include <android/log.h>
|
||||
#include <pthread.h>
|
||||
|
||||
static int pfd[2];
|
||||
static pthread_t loggingThread;
|
||||
static const char *LOG_TAG = "colorchord";
|
||||
|
@ -45,28 +60,28 @@ static void *loggingFunction(void*v) {
|
|||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
struct SoundDriver * sd;
|
||||
|
||||
|
||||
|
||||
#if defined(WIN32) || defined(USE_WINDOWS)
|
||||
#include <winsock2.h>
|
||||
#include <windows.h>
|
||||
|
||||
#define ESCAPE_KEY 0x1B
|
||||
|
||||
void WindowsTerm()
|
||||
void HandleDestroy()
|
||||
{
|
||||
CloseSound( sd );
|
||||
CNFAClose( sd );
|
||||
}
|
||||
|
||||
|
||||
#else
|
||||
|
||||
#define ESCAPE_KEY 65307
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
float DeltaFrameTime = 0;
|
||||
double Now = 0;
|
||||
|
||||
|
@ -124,10 +139,10 @@ void HandleMotion( int x, int y, int mask )
|
|||
{
|
||||
}
|
||||
|
||||
void SoundCB( float * out, float * in, int samplesr, int * samplesp, struct SoundDriver * sd )
|
||||
void SoundCB( struct CNFADriver * sd, short * in, short * out, int samplesr, int samplesp )
|
||||
{
|
||||
int channelin = sd->channelsRec;
|
||||
// int channelout = sd->channelsPlay;
|
||||
int channelout = sd->channelsPlay;
|
||||
//*samplesp = 0;
|
||||
// int process_channels = (MAX_CHANNELS < channelin)?MAX_CHANNELS:channelin;
|
||||
|
||||
|
@ -136,60 +151,61 @@ void SoundCB( float * out, float * in, int samplesr, int * samplesp, struct Soun
|
|||
int i;
|
||||
int j;
|
||||
|
||||
for( i = 0; i < samplesr; i++ )
|
||||
if( in )
|
||||
{
|
||||
if( out )
|
||||
for( i = 0; i < samplesr; i++ )
|
||||
{
|
||||
for( j = 0; j < channelin; j++ )
|
||||
if( sample_channel < 0 )
|
||||
{
|
||||
out[i*channelin+j] = 0;
|
||||
}
|
||||
}
|
||||
float fo = 0;
|
||||
for( j = 0; j < channelin; j++ )
|
||||
{
|
||||
float f = in[i*channelin+j] / 32767.;
|
||||
if( f >= -1 && f <= 1 )
|
||||
{
|
||||
fo += f;
|
||||
}
|
||||
else
|
||||
{
|
||||
fo += (f>0)?1:-1;
|
||||
// printf( "Sound fault A %d/%d %d/%d %f\n", j, channelin, i, samplesr, f );
|
||||
}
|
||||
}
|
||||
|
||||
if( sample_channel < 0 )
|
||||
{
|
||||
float fo = 0;
|
||||
for( j = 0; j < channelin; j++ )
|
||||
fo /= channelin;
|
||||
sound[soundhead] = fo*in_amplitude;
|
||||
soundhead = (soundhead+1)%SOUNDCBSIZE;
|
||||
}
|
||||
else
|
||||
{
|
||||
float f = in[i*channelin+j];
|
||||
if( f >= -1 && f <= 1 )
|
||||
{
|
||||
fo += f;
|
||||
}
|
||||
else
|
||||
{
|
||||
fo += (f>0)?1:-1;
|
||||
// printf( "Sound fault A %d/%d %d/%d %f\n", j, channelin, i, samplesr, f );
|
||||
float f = in[i*channelin+sample_channel] / 32767.;
|
||||
|
||||
if( f > 1 || f < -1 )
|
||||
{
|
||||
f = (f>0)?1:-1;
|
||||
}
|
||||
|
||||
|
||||
//printf( "Sound fault B %d/%d\n", i, samplesr );
|
||||
sound[soundhead] = f*in_amplitude;
|
||||
soundhead = (soundhead+1)%SOUNDCBSIZE;
|
||||
|
||||
}
|
||||
|
||||
fo /= channelin;
|
||||
sound[soundhead] = fo*in_amplitude;
|
||||
soundhead = (soundhead+1)%SOUNDCBSIZE;
|
||||
}
|
||||
else
|
||||
{
|
||||
float f = in[i*channelin+sample_channel];
|
||||
|
||||
if( f > 1 || f < -1 )
|
||||
{
|
||||
f = (f>0)?1:-1;
|
||||
}
|
||||
|
||||
|
||||
//printf( "Sound fault B %d/%d\n", i, samplesr );
|
||||
sound[soundhead] = f*in_amplitude;
|
||||
soundhead = (soundhead+1)%SOUNDCBSIZE;
|
||||
|
||||
}
|
||||
SoundEventHappened( samplesr, in, 0, channelin );
|
||||
}
|
||||
|
||||
SoundEventHappened( samplesr, in, 0, channelin );
|
||||
|
||||
if( out )
|
||||
{
|
||||
for( j = 0; j < samplesp * channelout; j++ )
|
||||
{
|
||||
out[j] = 0;
|
||||
}
|
||||
SoundEventHappened( samplesr, out, 1, sd->channelsPlay );
|
||||
}
|
||||
*samplesp = samplesr;
|
||||
|
||||
|
||||
}
|
||||
|
||||
#ifdef ANDROID
|
||||
|
@ -309,7 +325,9 @@ int main(int argc, char ** argv)
|
|||
|
||||
|
||||
//Initialize Sound
|
||||
sd = InitSound( sound_source, &SoundCB );
|
||||
sd = CNFAInit( sound_source, "colorchord", &SoundCB, GetParameterI( "samplerate", 44100 ),
|
||||
GetParameterI( "channels", 2 ), GetParameterI( "channels", 2 ), GetParameterI( "buffer", 1024 ),
|
||||
GetParameterS( "devrecord", 0 ), GetParameterS( "devplay", 0 ) );
|
||||
|
||||
if( !sd )
|
||||
{
|
||||
|
@ -317,7 +335,7 @@ int main(int argc, char ** argv)
|
|||
return -1;
|
||||
}
|
||||
|
||||
nf = CreateNoteFinder( sd->spsRec );
|
||||
nf = CreateNoteFinder( sd->sps );
|
||||
|
||||
//Once everything was reinitialized, re-read the ini files.
|
||||
SetEnvValues( 1 );
|
||||
|
|
|
@ -1 +1 @@
|
|||
Subproject commit e5acb751f337f3ae9e558e98907be8e3d6f8381f
|
||||
Subproject commit 55fa52d1eb355baf1456aa55251e722500a32ab8
|
|
@ -1,108 +0,0 @@
|
|||
//Copyright 2015 <>< Charles Lohr under the ColorChord License.
|
||||
|
||||
#include "sound.h"
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
static SoundInitFn * SoundDrivers[MAX_SOUND_DRIVERS];
|
||||
static char * SoundDriverNames[MAX_SOUND_DRIVERS]; //XXX: There's a bug in my compiler, this should be 'static'
|
||||
static int SoundDriverPriorities[MAX_SOUND_DRIVERS];
|
||||
/*
|
||||
void CleanupSound() __attribute__((destructor));
|
||||
void CleanupSound()
|
||||
{
|
||||
int i;
|
||||
for( i = 0; i < MAX_SOUND_DRIVERS; i++ )
|
||||
{
|
||||
if( SoundDriverNames[i] )
|
||||
{
|
||||
free( SoundDriverNames[i] );
|
||||
}
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
void RegSound( int priority, const char * name, SoundInitFn * fn )
|
||||
{
|
||||
int j;
|
||||
|
||||
if( priority <= 0 )
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
for( j = MAX_SOUND_DRIVERS-1; j >= 0; j-- )
|
||||
{
|
||||
//Cruise along, find location to insert
|
||||
if( j > 0 && ( !SoundDrivers[j-1] || SoundDriverPriorities[j-1] < priority ) )
|
||||
{
|
||||
SoundDrivers[j] = SoundDrivers[j-1];
|
||||
SoundDriverNames[j] = SoundDriverNames[j-1];
|
||||
SoundDriverPriorities[j] = SoundDriverPriorities[j-1];
|
||||
}
|
||||
else
|
||||
{
|
||||
SoundDrivers[j] = fn;
|
||||
SoundDriverNames[j] = strdup( name );
|
||||
SoundDriverPriorities[j] = priority;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct SoundDriver * InitSound( const char * driver_name, SoundCBType cb )
|
||||
{
|
||||
int i;
|
||||
struct SoundDriver * ret = 0;
|
||||
if( driver_name == 0 || strlen( driver_name ) == 0 )
|
||||
{
|
||||
//Search for a driver.
|
||||
for( i = 0; i < MAX_SOUND_DRIVERS; i++ )
|
||||
{
|
||||
if( SoundDrivers[i] == 0 )
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
ret = SoundDrivers[i]( cb );
|
||||
if( ret )
|
||||
{
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
printf( "Initializing sound. Recommended driver: %s\n", driver_name );
|
||||
for( i = 0; i < MAX_SOUND_DRIVERS; i++ )
|
||||
{
|
||||
if( SoundDrivers[i] == 0 )
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
if( strcmp( SoundDriverNames[i], driver_name ) == 0 )
|
||||
{
|
||||
return SoundDrivers[i]( cb );
|
||||
}
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int SoundState( struct SoundDriver * soundobject )
|
||||
{
|
||||
if( soundobject )
|
||||
{
|
||||
return soundobject->SoundStateFn( soundobject );
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
void CloseSound( struct SoundDriver * soundobject )
|
||||
{
|
||||
if( soundobject )
|
||||
{
|
||||
soundobject->CloseFn( soundobject );
|
||||
}
|
||||
}
|
||||
|
|
@ -1,41 +0,0 @@
|
|||
//Copyright 2015 <>< Charles Lohr under the ColorChord License.
|
||||
|
||||
#ifndef _SOUND_H
|
||||
#define _SOUND_H
|
||||
|
||||
#define MAX_SOUND_DRIVERS 10
|
||||
|
||||
struct SoundDriver;
|
||||
|
||||
typedef void(*SoundCBType)( float * out, float * in, int samplesr, int * samplesp, struct SoundDriver * sd );
|
||||
typedef void*(SoundInitFn)( SoundCBType cb );
|
||||
|
||||
struct SoundDriver
|
||||
{
|
||||
void (*CloseFn)( void * object );
|
||||
int (*SoundStateFn)( struct SoundDriver * object );
|
||||
SoundCBType callback;
|
||||
int channelsPlay;
|
||||
int spsPlay;
|
||||
int channelsRec;
|
||||
int spsRec;
|
||||
|
||||
//More fields may exist on a per-sound-driver basis
|
||||
};
|
||||
|
||||
//Accepts:
|
||||
// samplerate=44100;channels=2;devplay=default;devrecord=default;record=1;play=1;minavailcount=4096;stopthresh=1024;startthresh=4096;buffer=1024
|
||||
// buffer is in samples
|
||||
//If DriverName = 0 or empty, will try to find best driver.
|
||||
struct SoundDriver * InitSound( const char * driver_name, SoundCBType cb );
|
||||
int SoundState( struct SoundDriver * soundobject ); //returns 0 if okay, negative if faulted.
|
||||
void CloseSound( struct SoundDriver * soundobject );
|
||||
|
||||
//Called by various sound drivers. Notice priority must be greater than 0. Priority of 0 or less will not register.
|
||||
void RegSound( int priority, const char * name, SoundInitFn * fn );
|
||||
|
||||
#define REGISTER_SOUND( sounddriver, priority, name, function ) \
|
||||
void __attribute__((constructor)) REGISTER##sounddriver() { RegSound( priority, name, function ); }
|
||||
|
||||
#endif
|
||||
|
|
@ -1,364 +0,0 @@
|
|||
//Copyright 2015 <>< Charles Lohr under the ColorChord License.
|
||||
|
||||
#include "sound.h"
|
||||
#include "os_generic.h"
|
||||
#include "parameters.h"
|
||||
#include <alsa/asoundlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#define BUFFERSETS 4
|
||||
|
||||
#define BLOCKING
|
||||
|
||||
struct SoundDriverAlsa
|
||||
{
|
||||
void (*CloseFn)( struct SoundDriverAlsa * object );
|
||||
int (*SoundStateFn)( struct SoundDriverAlsa * object );
|
||||
SoundCBType callback;
|
||||
int channelsPlay;
|
||||
int spsPlay;
|
||||
int channelsRec;
|
||||
int spsRec;
|
||||
int alsa_fmt_s16le;
|
||||
|
||||
snd_pcm_uframes_t buffer;
|
||||
og_thread_t thread;
|
||||
snd_pcm_t *playback_handle;
|
||||
snd_pcm_t *record_handle;
|
||||
|
||||
//More fields may exist on a per-sound-driver basis
|
||||
};
|
||||
|
||||
static struct SoundDriverAlsa* InitASound( struct SoundDriverAlsa * r );
|
||||
|
||||
void CloseSoundAlsa( struct SoundDriverAlsa * r );
|
||||
|
||||
int SoundStateAlsa( struct SoundDriverAlsa * soundobject )
|
||||
{
|
||||
return ((soundobject->playback_handle)?1:0) | ((soundobject->record_handle)?2:0);
|
||||
}
|
||||
|
||||
void CloseSoundAlsa( struct SoundDriverAlsa * r )
|
||||
{
|
||||
if( r )
|
||||
{
|
||||
if( r->playback_handle ) snd_pcm_close (r->playback_handle);
|
||||
if( r->record_handle ) snd_pcm_close (r->record_handle);
|
||||
#ifdef BLOCKING
|
||||
OGUSleep(2000);
|
||||
OGCancelThread( r->thread );
|
||||
#endif
|
||||
free( r );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static int SetHWParams( snd_pcm_t * handle, int * samplerate, int * channels, snd_pcm_uframes_t * buffer, struct SoundDriverAlsa * a )
|
||||
{
|
||||
int err;
|
||||
snd_pcm_hw_params_t *hw_params;
|
||||
if ((err = snd_pcm_hw_params_malloc (&hw_params)) < 0) {
|
||||
fprintf (stderr, "cannot allocate hardware parameter structure (%s)\n",
|
||||
snd_strerror (err));
|
||||
return -1;
|
||||
}
|
||||
|
||||
if ((err = snd_pcm_hw_params_any (handle, hw_params)) < 0) {
|
||||
fprintf (stderr, "cannot initialize hardware parameter structure (%s)\n",
|
||||
snd_strerror (err));
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if ((err = snd_pcm_hw_params_set_access (handle, hw_params, SND_PCM_ACCESS_RW_INTERLEAVED)) < 0) {
|
||||
fprintf (stderr, "cannot set access type (%s)\n",
|
||||
snd_strerror (err));
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if ((err = snd_pcm_hw_params_set_format (handle, hw_params, SND_PCM_FORMAT_FLOAT )) < 0) {
|
||||
fprintf (stderr, "cannot set sample format (%s)\n",
|
||||
snd_strerror (err));
|
||||
|
||||
printf( "Trying backup: S16LE.\n" );
|
||||
if ((err = snd_pcm_hw_params_set_format (handle, hw_params, SND_PCM_FORMAT_S16_LE )) < 0) {
|
||||
fprintf (stderr, "cannot set sample format (%s)\n",
|
||||
snd_strerror (err));
|
||||
goto fail;
|
||||
}
|
||||
|
||||
a->alsa_fmt_s16le = 1;
|
||||
}
|
||||
|
||||
if ((err = snd_pcm_hw_params_set_rate_near (handle, hw_params, (unsigned int*)samplerate, 0)) < 0) {
|
||||
fprintf (stderr, "cannot set sample rate (%s)\n",
|
||||
snd_strerror (err));
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if ((err = snd_pcm_hw_params_set_channels (handle, hw_params, *channels)) < 0) {
|
||||
fprintf (stderr, "cannot set channel count (%s)\n",
|
||||
snd_strerror (err));
|
||||
goto fail;
|
||||
}
|
||||
|
||||
int dir = 0;
|
||||
if( (err = snd_pcm_hw_params_set_period_size_near(handle, hw_params, buffer, &dir)) < 0 )
|
||||
{
|
||||
fprintf( stderr, "cannot set period size. (%s)\n",
|
||||
snd_strerror(err) );
|
||||
goto fail;
|
||||
}
|
||||
|
||||
|
||||
if ((err = snd_pcm_hw_params (handle, hw_params)) < 0) {
|
||||
fprintf (stderr, "cannot set parameters (%s)\n",
|
||||
snd_strerror (err));
|
||||
goto fail;
|
||||
}
|
||||
|
||||
snd_pcm_hw_params_free (hw_params);
|
||||
return 0;
|
||||
fail:
|
||||
snd_pcm_hw_params_free (hw_params);
|
||||
return -2;
|
||||
}
|
||||
|
||||
|
||||
static int SetSWParams( snd_pcm_t * handle, int isrec )
|
||||
{
|
||||
snd_pcm_sw_params_t *sw_params;
|
||||
int err;
|
||||
//Time for software parameters:
|
||||
|
||||
if( !isrec )
|
||||
{
|
||||
if ((err = snd_pcm_sw_params_malloc (&sw_params)) < 0) {
|
||||
fprintf (stderr, "cannot allocate software parameters structure (%s)\n",
|
||||
snd_strerror (err));
|
||||
goto failhard;
|
||||
}
|
||||
if ((err = snd_pcm_sw_params_current (handle, sw_params)) < 0) {
|
||||
fprintf (stderr, "cannot initialize software parameters structure (%s) (%p)\n",
|
||||
snd_strerror (err), handle);
|
||||
goto fail;
|
||||
}
|
||||
if ((err = snd_pcm_sw_params_set_avail_min (handle, sw_params, GetParameterI( "minavailcount", 2048 ) )) < 0) {
|
||||
fprintf (stderr, "cannot set minimum available count (%s)\n",
|
||||
snd_strerror (err));
|
||||
goto fail;
|
||||
}
|
||||
if ((err = snd_pcm_sw_params_set_stop_threshold(handle, sw_params, GetParameterI( "stopthresh", 512 ))) < 0) {
|
||||
fprintf (stderr, "cannot set minimum available count (%s)\n",
|
||||
snd_strerror (err));
|
||||
goto fail;
|
||||
}
|
||||
if ((err = snd_pcm_sw_params_set_start_threshold(handle, sw_params, GetParameterI( "startthresh", 2048 ))) < 0) {
|
||||
fprintf (stderr, "cannot set minimum available count (%s)\n",
|
||||
snd_strerror (err));
|
||||
goto fail;
|
||||
}
|
||||
if ((err = snd_pcm_sw_params (handle, sw_params)) < 0) {
|
||||
fprintf (stderr, "cannot set software parameters (%s)\n",
|
||||
snd_strerror (err));
|
||||
goto fail;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
if ((err = snd_pcm_prepare (handle)) < 0) {
|
||||
fprintf (stderr, "cannot prepare audio interface for use (%s)\n",
|
||||
snd_strerror (err));
|
||||
goto fail;
|
||||
}
|
||||
|
||||
|
||||
return 0;
|
||||
fail:
|
||||
if( !isrec )
|
||||
{
|
||||
snd_pcm_sw_params_free (sw_params);
|
||||
}
|
||||
failhard:
|
||||
return -1;
|
||||
}
|
||||
|
||||
#ifdef BLOCKING
|
||||
static void * SoundThread( void * v )
|
||||
{
|
||||
int i;
|
||||
struct SoundDriverAlsa * a = (struct SoundDriverAlsa*)v;
|
||||
float * bufr[BUFFERSETS];
|
||||
float * bufp[BUFFERSETS];
|
||||
|
||||
for(i = 0; i < BUFFERSETS; i++ )
|
||||
{
|
||||
bufr[i] = malloc( a->buffer * sizeof(float) * a->channelsRec );
|
||||
bufp[i] = malloc( a->buffer * sizeof(float) * a->channelsPlay );
|
||||
}
|
||||
|
||||
while( a->record_handle || a->playback_handle )
|
||||
{
|
||||
int err;
|
||||
|
||||
i = (i+1)%BUFFERSETS;
|
||||
|
||||
if( a->record_handle )
|
||||
{
|
||||
if( (err = snd_pcm_readi (a->record_handle, bufr[i], a->buffer)) != a->buffer)
|
||||
{
|
||||
fprintf (stderr, "read from audio interface failed (%s)\n",
|
||||
snd_strerror (err));
|
||||
if( a->record_handle ) snd_pcm_close (a->record_handle);
|
||||
a->record_handle = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
//has_rec = 1;
|
||||
}
|
||||
}
|
||||
|
||||
if( a->alsa_fmt_s16le )
|
||||
{
|
||||
//Hacky: Turns out data was s16le.
|
||||
int16_t * dat = (int16_t*)bufr[i];
|
||||
float * dot = bufr[i];
|
||||
int i;
|
||||
int len = a->buffer;
|
||||
for( i = len-1; i >= 0; i-- )
|
||||
{
|
||||
dot[i] = dat[i]/32768.0;
|
||||
}
|
||||
}
|
||||
//Do our callback.
|
||||
int playbacksamples = 0;
|
||||
a->callback( bufp[i], bufr[i], a->buffer, &playbacksamples, (struct SoundDriver*)a );
|
||||
//playbacksamples *= sizeof(float) * a->channelsPlay;
|
||||
|
||||
if( a->playback_handle )
|
||||
{
|
||||
if ((err = snd_pcm_writei (a->playback_handle, bufp[i], playbacksamples)) != playbacksamples)
|
||||
{
|
||||
fprintf (stderr, "write to audio interface failed (%s)\n",
|
||||
snd_strerror (err));
|
||||
if( a->playback_handle ) snd_pcm_close (a->playback_handle);
|
||||
a->playback_handle = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//Fault happened, re-initialize?
|
||||
InitASound( a );
|
||||
return 0;
|
||||
}
|
||||
#else
|
||||
|
||||
//Handle callback
|
||||
|
||||
static struct SoundDriverAlsa * reccb;
|
||||
static int record_callback (snd_pcm_sframes_t nframes)
|
||||
{
|
||||
int err;
|
||||
|
||||
// printf ("playback callback called with %u frames\n", nframes);
|
||||
|
||||
/* ... fill buf with data ... */
|
||||
|
||||
if ((err = snd_pcm_writei (playback_handle, buf, nframes)) < 0) {
|
||||
fprintf (stderr, "write failed (%s)\n", snd_strerror (err));
|
||||
}
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
static struct SoundDriverAlsa * InitASound( struct SoundDriverAlsa * r )
|
||||
{
|
||||
int err;
|
||||
if( GetParameterI( "play", 0 ) )
|
||||
{
|
||||
if ((err = snd_pcm_open (&r->playback_handle, GetParameterS( "devplay", "default" ), SND_PCM_STREAM_PLAYBACK, 0)) < 0) {
|
||||
fprintf (stderr, "cannot open output audio device (%s)\n",
|
||||
snd_strerror (err));
|
||||
goto fail;
|
||||
}
|
||||
}
|
||||
|
||||
if( GetParameterI( "record", 1 ) )
|
||||
{
|
||||
if ((err = snd_pcm_open (&r->record_handle, GetParameterS( "devrecord", "default" ), SND_PCM_STREAM_CAPTURE, 0)) < 0) {
|
||||
fprintf (stderr, "cannot open input audio device (%s)\n",
|
||||
snd_strerror (err));
|
||||
goto fail;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
if( r->playback_handle )
|
||||
{
|
||||
if( SetHWParams( r->playback_handle, &r->spsPlay, &r->channelsPlay, &r->buffer, r ) < 0 )
|
||||
goto fail;
|
||||
if( SetSWParams( r->playback_handle, 0 ) < 0 )
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if( r->record_handle )
|
||||
{
|
||||
if( SetHWParams( r->record_handle, &r->spsRec, &r->channelsRec, &r->buffer, r ) < 0 )
|
||||
goto fail;
|
||||
if( SetSWParams( r->record_handle, 1 ) < 0 )
|
||||
goto fail;
|
||||
}
|
||||
|
||||
if( r->playback_handle && r->record_handle )
|
||||
{
|
||||
snd_pcm_link ( r->playback_handle, r->record_handle );
|
||||
}
|
||||
|
||||
#ifdef BLOCKING
|
||||
r->thread = OGCreateThread( SoundThread, r );
|
||||
#else
|
||||
reccb = r;
|
||||
//handle interrupt
|
||||
#endif
|
||||
return r;
|
||||
|
||||
fail:
|
||||
if( r )
|
||||
{
|
||||
if( r->playback_handle ) snd_pcm_close (r->playback_handle);
|
||||
if( r->record_handle ) snd_pcm_close (r->record_handle);
|
||||
free( r );
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void * InitSoundAlsa( SoundCBType cb )
|
||||
{
|
||||
struct SoundDriverAlsa * r = malloc( sizeof( struct SoundDriverAlsa ) );
|
||||
|
||||
r->CloseFn = CloseSoundAlsa;
|
||||
r->SoundStateFn = SoundStateAlsa;
|
||||
r->callback = cb;
|
||||
|
||||
r->spsPlay = GetParameterI( "samplerate", 44100 );
|
||||
r->channelsPlay = GetParameterI( "channels", 2 );
|
||||
r->spsRec = r->spsPlay;
|
||||
r->channelsRec = r->channelsPlay;
|
||||
|
||||
r->playback_handle = 0;
|
||||
r->record_handle = 0;
|
||||
r->buffer = GetParameterI( "buffer", 1024 );
|
||||
|
||||
r->alsa_fmt_s16le = 0;
|
||||
|
||||
|
||||
return InitASound(r);
|
||||
}
|
||||
|
||||
REGISTER_SOUND( AlsaSound, 10, "ALSA", InitSoundAlsa );
|
||||
|
|
@ -1,244 +0,0 @@
|
|||
//Copyright 2019-2020 <>< Charles Lohr under the ColorChord License.
|
||||
// This should be used with rawdrawandroid
|
||||
|
||||
#include "sound.h"
|
||||
#include "os_generic.h"
|
||||
#include <pthread.h> //Using android threads not os_generic threads.
|
||||
#include <assert.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#ifndef NO_SOUND_PARAMETERS
|
||||
#include "parameters.h"
|
||||
#else
|
||||
#define GetParameterI( x, y ) (y)
|
||||
#define GetParameterS( x, y ) (y)
|
||||
#endif
|
||||
|
||||
|
||||
//based on https://github.com/android/ndk-samples/blob/master/native-audio/app/src/main/cpp/native-audio-jni.c
|
||||
|
||||
// for native audio
|
||||
#include <SLES/OpenSLES.h>
|
||||
#include <SLES/OpenSLES_Android.h>
|
||||
|
||||
#include <android_native_app_glue.h>
|
||||
#include <android/log.h>
|
||||
#include <jni.h>
|
||||
#include <native_activity.h>
|
||||
|
||||
#define LOGI(...) ((void)__android_log_print(ANDROID_LOG_INFO, APPNAME, __VA_ARGS__))
|
||||
#define printf( x...) LOGI( x )
|
||||
|
||||
#define RECORDER_FRAMES 1024
|
||||
|
||||
#define BUFFERSETS 4
|
||||
|
||||
#define BLOCKING
|
||||
|
||||
//Across all sound systems.
|
||||
static pthread_mutex_t audioEngineLock = PTHREAD_MUTEX_INITIALIZER;
|
||||
|
||||
struct SoundDriverAndroid
|
||||
{
|
||||
void (*CloseFn)( struct SoundDriverAndroid * object );
|
||||
int (*SoundStateFn)( struct SoundDriverAndroid * object );
|
||||
SoundCBType callback;
|
||||
SLObjectItf engineObject;
|
||||
SLEngineItf engineEngine;
|
||||
SLRecordItf recorderRecord;
|
||||
SLObjectItf recorderObject;
|
||||
SLAndroidSimpleBufferQueueItf recorderBufferQueue;
|
||||
unsigned recorderSize;
|
||||
|
||||
short recorderBuffer[RECORDER_FRAMES];
|
||||
};
|
||||
|
||||
|
||||
void bqRecorderCallback(SLAndroidSimpleBufferQueueItf bq, void *context)
|
||||
{
|
||||
struct SoundDriverAndroid * r = (struct SoundDriverAndroid*)context;
|
||||
int samplesp = 0;
|
||||
float buffout[RECORDER_FRAMES];
|
||||
int i;
|
||||
short * rb = r->recorderBuffer;
|
||||
for( i = 0; i < RECORDER_FRAMES; i++ ) buffout[i] = (rb[i]+0.5)/32767.5;
|
||||
r->callback( 0, buffout, RECORDER_FRAMES, &samplesp, r );
|
||||
(*r->recorderBufferQueue)->Enqueue(r->recorderBufferQueue, r->recorderBuffer, sizeof(r->recorderBuffer));
|
||||
}
|
||||
|
||||
static struct SoundDriverAndroid* InitAndroidSound( struct SoundDriverAndroid * r )
|
||||
{
|
||||
SLresult result;
|
||||
LOGI( "Starting InitAndroidSound\n" );
|
||||
// create engine
|
||||
result = slCreateEngine(&r->engineObject, 0, NULL, 0, NULL, NULL);
|
||||
assert(SL_RESULT_SUCCESS == result);
|
||||
(void)result;
|
||||
|
||||
// realize the engine
|
||||
result = (*r->engineObject)->Realize(r->engineObject, SL_BOOLEAN_FALSE);
|
||||
assert(SL_RESULT_SUCCESS == result);
|
||||
(void)result;
|
||||
|
||||
// get the engine interface, which is needed in order to create other objects
|
||||
result = (*r->engineObject)->GetInterface(r->engineObject, SL_IID_ENGINE, &r->engineEngine);
|
||||
assert(SL_RESULT_SUCCESS == result);
|
||||
(void)result;
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
// configure audio source
|
||||
SLDataLocator_IODevice loc_dev = {SL_DATALOCATOR_IODEVICE, SL_IODEVICE_AUDIOINPUT,
|
||||
SL_DEFAULTDEVICEID_AUDIOINPUT, NULL};
|
||||
SLDataSource audioSrc = {&loc_dev, NULL};
|
||||
|
||||
// configure audio sink
|
||||
SLDataLocator_AndroidSimpleBufferQueue loc_bq = {SL_DATALOCATOR_ANDROIDSIMPLEBUFFERQUEUE, 2};
|
||||
|
||||
SLDataFormat_PCM format_pcm ={
|
||||
SL_DATAFORMAT_PCM,
|
||||
1,
|
||||
SL_SAMPLINGRATE_16,
|
||||
SL_PCMSAMPLEFORMAT_FIXED_16,
|
||||
SL_PCMSAMPLEFORMAT_FIXED_16,
|
||||
SL_SPEAKER_FRONT_CENTER,
|
||||
SL_BYTEORDER_LITTLEENDIAN,
|
||||
};
|
||||
|
||||
SLDataSink audioSnk = {&loc_bq, &format_pcm};
|
||||
|
||||
// create audio recorder
|
||||
// (requires the RECORD_AUDIO permission)
|
||||
const SLInterfaceID id[1] = {SL_IID_ANDROIDSIMPLEBUFFERQUEUE};
|
||||
const SLboolean req[1] = {SL_BOOLEAN_TRUE};
|
||||
result = (*r->engineEngine)->CreateAudioRecorder(r->engineEngine, &r->recorderObject, &audioSrc,
|
||||
&audioSnk, 1, id, req);
|
||||
if (SL_RESULT_SUCCESS != result) {
|
||||
LOGI( "CreateAudioRecorder failed\n" );
|
||||
return JNI_FALSE;
|
||||
}
|
||||
|
||||
// realize the audio recorder
|
||||
result = (*r->recorderObject)->Realize(r->recorderObject, SL_BOOLEAN_FALSE);
|
||||
if (SL_RESULT_SUCCESS != result) {
|
||||
LOGI( "AudioRecorder Realize failed: %d\n", result );
|
||||
return JNI_FALSE;
|
||||
}
|
||||
|
||||
// get the record interface
|
||||
result = (*r->recorderObject)->GetInterface(r->recorderObject, SL_IID_RECORD, &r->recorderRecord);
|
||||
assert(SL_RESULT_SUCCESS == result);
|
||||
(void)result;
|
||||
|
||||
// get the buffer queue interface
|
||||
result = (*r->recorderObject)->GetInterface(r->recorderObject, SL_IID_ANDROIDSIMPLEBUFFERQUEUE,
|
||||
&r->recorderBufferQueue);
|
||||
assert(SL_RESULT_SUCCESS == result);
|
||||
(void)result;
|
||||
|
||||
// register callback on the buffer queue
|
||||
result = (*r->recorderBufferQueue)->RegisterCallback(r->recorderBufferQueue, bqRecorderCallback, r);
|
||||
assert(SL_RESULT_SUCCESS == result);
|
||||
(void)result;
|
||||
|
||||
|
||||
assert( !pthread_mutex_trylock(&audioEngineLock));
|
||||
// in case already recording, stop recording and clear buffer queue
|
||||
result = (*r->recorderRecord)->SetRecordState(r->recorderRecord, SL_RECORDSTATE_STOPPED);
|
||||
assert(SL_RESULT_SUCCESS == result);
|
||||
(void)result;
|
||||
result = (*r->recorderBufferQueue)->Clear(r->recorderBufferQueue);
|
||||
assert(SL_RESULT_SUCCESS == result);
|
||||
(void)result;
|
||||
|
||||
// the buffer is not valid for playback yet
|
||||
r->recorderSize = 0;
|
||||
|
||||
// enqueue an empty buffer to be filled by the recorder
|
||||
// (for streaming recording, we would enqueue at least 2 empty buffers to start things off)
|
||||
result = (*r->recorderBufferQueue)->Enqueue(r->recorderBufferQueue, r->recorderBuffer, sizeof(r->recorderBuffer));
|
||||
// the most likely other result is SL_RESULT_BUFFER_INSUFFICIENT,
|
||||
// which for this code example would indicate a programming error
|
||||
assert(SL_RESULT_SUCCESS == result);
|
||||
(void)result;
|
||||
|
||||
// start recording
|
||||
result = (*r->recorderRecord)->SetRecordState(r->recorderRecord, SL_RECORDSTATE_RECORDING);
|
||||
assert(SL_RESULT_SUCCESS == result);
|
||||
(void)result;
|
||||
|
||||
LOGI( "Complete Init Sound Android\n" );
|
||||
return r;
|
||||
}
|
||||
|
||||
void CloseSoundAndroid( struct SoundDriverAndroid * r );
|
||||
|
||||
int SoundStateAndroid( struct SoundDriverAndroid * soundobject )
|
||||
{
|
||||
return ((soundobject->recorderObject)?1:0) | ((soundobject->recorderObject)?2:0);
|
||||
}
|
||||
|
||||
void CloseSoundAndroid( struct SoundDriverAndroid * r )
|
||||
{
|
||||
// destroy audio recorder object, and invalidate all associated interfaces
|
||||
if (r->recorderObject != NULL) {
|
||||
(*r->recorderObject)->Destroy(r->recorderObject);
|
||||
r->recorderObject = NULL;
|
||||
r->recorderRecord = NULL;
|
||||
r->recorderBufferQueue = NULL;
|
||||
}
|
||||
|
||||
|
||||
// destroy engine object, and invalidate all associated interfaces
|
||||
if (r->engineObject != NULL) {
|
||||
(*r->engineObject)->Destroy(r->engineObject);
|
||||
r->engineObject = NULL;
|
||||
r->engineEngine = NULL;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
int AndroidHasPermissions(const char* perm_name);
|
||||
void AndroidRequestAppPermissions(const char * perm);
|
||||
|
||||
|
||||
void * InitSoundAndroid( SoundCBType cb )
|
||||
{
|
||||
int hasperm = AndroidHasPermissions( "RECORD_AUDIO" );
|
||||
if( !hasperm )
|
||||
{
|
||||
AndroidRequestAppPermissions( "RECORD_AUDIO" );
|
||||
}
|
||||
|
||||
struct SoundDriverAndroid * r = (struct SoundDriverAndroid *)malloc( sizeof( struct SoundDriverAndroid ) );
|
||||
memset( r, 0, sizeof( *r) );
|
||||
r->CloseFn = CloseSoundAndroid;
|
||||
r->SoundStateFn = SoundStateAndroid;
|
||||
r->callback = cb;
|
||||
r->engineObject = 0;
|
||||
r->engineEngine = 0;
|
||||
/*
|
||||
r->spsPlay = GetParameterI( "samplerate", 44100 );
|
||||
r->channelsPlay = GetParameterI( "channels", 2 );
|
||||
r->spsRec = r->spsPlay;
|
||||
r->channelsRec = r->channelsPlay;
|
||||
|
||||
r->playback_handle = 0;
|
||||
r->record_handle = 0;
|
||||
r->buffer = GetParameterI( "buffer", 1024 );
|
||||
|
||||
r->Android_fmt_s16le = 0;
|
||||
|
||||
*/
|
||||
return InitAndroidSound(r);
|
||||
}
|
||||
|
||||
//Tricky: On Android, this can't actually run before main. Have to manually execute it.
|
||||
|
||||
REGISTER_SOUND( AndroidSound, 10, "ANDROID", InitSoundAndroid );
|
||||
|
|
@ -1,45 +0,0 @@
|
|||
//Copyright 2015 <>< Charles Lohr under the ColorChord License.
|
||||
|
||||
#include "sound.h"
|
||||
#include "os_generic.h"
|
||||
#include <stdlib.h>
|
||||
#include "parameters.h"
|
||||
|
||||
struct SoundDriverNull
|
||||
{
|
||||
void (*CloseFn)( struct SoundDriverNull * object );
|
||||
int (*SoundStateFn)( struct SoundDriverNull * object );
|
||||
SoundCBType soundcb;
|
||||
int channelsPlay;
|
||||
int spsPlay;
|
||||
int channelsRec;
|
||||
int spsRec;
|
||||
};
|
||||
|
||||
void CloseSoundNull( struct SoundDriverNull * object )
|
||||
{
|
||||
free( object );
|
||||
}
|
||||
|
||||
int SoundStateNull( struct SoundDriverNull * object )
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
void * InitSoundNull( SoundCBType cb )
|
||||
{
|
||||
struct SoundDriverNull * r = malloc( sizeof( struct SoundDriverNull ) );
|
||||
r->CloseFn = CloseSoundNull;
|
||||
r->SoundStateFn = SoundStateNull;
|
||||
r->soundcb = cb;
|
||||
r->spsPlay = GetParameterI( "samplerate", 44100 );
|
||||
r->channelsPlay = GetParameterI( "channels", 2 );
|
||||
r->spsRec = r->spsPlay;
|
||||
r->channelsRec = r->channelsRec;
|
||||
return r;
|
||||
}
|
||||
|
||||
|
||||
REGISTER_SOUND( NullSound, 1, "NULL", InitSoundNull );
|
||||
|
|
@ -1,379 +0,0 @@
|
|||
//Copyright 2015 <>< Charles Lohr under the ColorChord License.
|
||||
|
||||
//This file is really rough. Full duplex doesn't seem to work hardly at all.
|
||||
|
||||
|
||||
#include "sound.h"
|
||||
#include "os_generic.h"
|
||||
#include "parameters.h"
|
||||
#include <stdlib.h>
|
||||
|
||||
#include <pulse/simple.h>
|
||||
#include <pulse/pulseaudio.h>
|
||||
#include <pulse/error.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#define BUFFERSETS 3
|
||||
|
||||
|
||||
//from http://www.freedesktop.org/wiki/Software/PulseAudio/Documentation/Developer/Clients/Samples/AsyncPlayback/
|
||||
//also http://maemo.org/api_refs/5.0/5.0-final/pulseaudio/pacat_8c-example.html
|
||||
|
||||
|
||||
struct SoundDriverPulse
|
||||
{
|
||||
void (*CloseFn)( struct SoundDriverPulse * object );
|
||||
int (*SoundStateFn)( struct SoundDriverPulse * object );
|
||||
SoundCBType callback;
|
||||
int channelsPlay;
|
||||
int spsPlay;
|
||||
int channelsRec;
|
||||
int spsRec;
|
||||
|
||||
const char * sourceName;
|
||||
og_thread_t thread;
|
||||
pa_stream * play;
|
||||
pa_stream * rec;
|
||||
pa_context * pa_ctx;
|
||||
pa_mainloop *pa_ml;
|
||||
int pa_ready;
|
||||
int buffer;
|
||||
//More fields may exist on a per-sound-driver basis
|
||||
};
|
||||
|
||||
|
||||
|
||||
void CloseSoundPulse( struct SoundDriverPulse * r );
|
||||
|
||||
int SoundStatePulse( struct SoundDriverPulse * soundobject )
|
||||
{
|
||||
return ((soundobject->play)?1:0) | ((soundobject->rec)?2:0);
|
||||
}
|
||||
|
||||
void CloseSoundPulse( struct SoundDriverPulse * r )
|
||||
{
|
||||
if( r )
|
||||
{
|
||||
if( r->play )
|
||||
{
|
||||
pa_stream_unref (r->play);
|
||||
r->play = 0;
|
||||
}
|
||||
|
||||
if( r->rec )
|
||||
{
|
||||
pa_stream_unref (r->rec);
|
||||
r->rec = 0;
|
||||
}
|
||||
OGUSleep(2000);
|
||||
OGCancelThread( r->thread );
|
||||
free( r );
|
||||
}
|
||||
}
|
||||
|
||||
static void * SoundThread( void * v )
|
||||
{
|
||||
struct SoundDriverPulse * r = (struct SoundDriverPulse*)v;
|
||||
while(1)
|
||||
{
|
||||
pa_mainloop_iterate( r->pa_ml, 1, NULL );
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
/*
|
||||
int i;
|
||||
int error;
|
||||
struct SoundDriverPulse * r = (struct SoundDriverPulse*)v;
|
||||
|
||||
float * bufr[BUFFERSETS];
|
||||
float * bufp[BUFFERSETS];
|
||||
|
||||
for(i = 0; i < BUFFERSETS; i++ )
|
||||
{
|
||||
bufr[i] = malloc( r->buffer * sizeof(float) * r->channelsRec );
|
||||
bufp[i] = malloc( r->buffer * sizeof(float) * r->channelsPlay );
|
||||
}
|
||||
|
||||
while( r->play || r->rec )
|
||||
{
|
||||
i = (i+1)%BUFFERSETS;
|
||||
|
||||
if( r->rec )
|
||||
{
|
||||
if (pa_stream_read(r->rec, bufr[i], r->buffer * sizeof(float) * r->channelsRec, &error) < 0) {
|
||||
fprintf(stderr, __FILE__": pa_stream_write() failed: %s\n", pa_strerror(error));
|
||||
pa_stream_unref( r->play );
|
||||
r->rec = 0;
|
||||
}
|
||||
}
|
||||
|
||||
int playbacksamples = 0;
|
||||
r->callback( bufp[i], bufr[i], r->buffer, &playbacksamples, (struct SoundDriver*)r );
|
||||
playbacksamples *= sizeof( float ) * r->channelsPlay;
|
||||
|
||||
if( r->play )
|
||||
{
|
||||
if (pa_stream_write(r->play, bufp[i], playbacksamples, NULL, 0LL, PA_SEEK_RELATIVE) < 0) {
|
||||
fprintf(stderr, __FILE__": pa_stream_write() failed: %s\n", pa_strerror(error));
|
||||
pa_stream_unref( r->play );
|
||||
r->play = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}*/
|
||||
|
||||
static void stream_request_cb(pa_stream *s, size_t length, void *userdata) {
|
||||
// pa_usec_t usec;
|
||||
|
||||
struct SoundDriverPulse * r = (struct SoundDriverPulse*)userdata;
|
||||
if( r->rec )
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
//Neat: You might want this:
|
||||
|
||||
pa_stream_get_latency(s,&usec,&neg);
|
||||
|
||||
if (sampleoffs*2 + length > sizeof(sampledata))
|
||||
{
|
||||
sampleoffs = 0;
|
||||
}
|
||||
|
||||
if (length > sizeof(sampledata)) {
|
||||
length = sizeof(sampledata);
|
||||
}
|
||||
|
||||
*/
|
||||
|
||||
|
||||
// pa_stream_write(s, &sampledata[sampleoffs], length, NULL, 0LL, PA_SEEK_RELATIVE);
|
||||
int playbacksamples = 0;
|
||||
float bufr[r->buffer*r->channelsRec];
|
||||
float bufp[r->buffer*r->channelsPlay];
|
||||
|
||||
r->callback( bufp, bufr, r->buffer, &playbacksamples, (struct SoundDriver*)r );
|
||||
//playbacksamples *= sizeof( float ) * r->channelsPlay;
|
||||
|
||||
pa_stream_write(r->play, &bufp, playbacksamples, NULL, 0LL, PA_SEEK_RELATIVE);
|
||||
|
||||
}
|
||||
|
||||
|
||||
static void stream_record_cb(pa_stream *s, size_t length, void *userdata) {
|
||||
// pa_usec_t usec;
|
||||
// int neg;
|
||||
|
||||
struct SoundDriverPulse * r = (struct SoundDriverPulse*)userdata;
|
||||
|
||||
/* pa_stream_get_latency(s,&usec,&neg);
|
||||
printf(" latency %8d us\n",(int)usec);
|
||||
|
||||
if (sampleoffs*2 + length > sizeof(sampledata))
|
||||
{
|
||||
sampleoffs = 0;
|
||||
}
|
||||
|
||||
if (length > sizeof(sampledata)) {
|
||||
length = sizeof(sampledata);
|
||||
}*/
|
||||
|
||||
int playbacksamples = 0;
|
||||
float * bufr;
|
||||
|
||||
if (pa_stream_peek(r->rec, (void*)&bufr, &length) < 0) {
|
||||
fprintf(stderr, ("pa_stream_peek() failed: %s\n"), pa_strerror(pa_context_errno(r->pa_ctx)));
|
||||
return;
|
||||
}
|
||||
|
||||
float * buffer;
|
||||
buffer = pa_xmalloc(length);
|
||||
memcpy(buffer, bufr, length);
|
||||
pa_stream_drop(r->rec);
|
||||
|
||||
float bufp[length*r->channelsPlay];
|
||||
r->callback( bufp, buffer, length/sizeof(float)/r->channelsRec, &playbacksamples, (struct SoundDriver*)r );
|
||||
//playbacksamples *= sizeof( float ) * r->channelsPlay;
|
||||
pa_xfree( buffer );
|
||||
if( r->play )
|
||||
pa_stream_write(r->play, &bufp, playbacksamples*sizeof(float)*r->channelsPlay, NULL, 0LL, PA_SEEK_RELATIVE);
|
||||
}
|
||||
|
||||
|
||||
|
||||
static void stream_underflow_cb(pa_stream *s, void *userdata) {
|
||||
// We increase the latency by 50% if we get 6 underflows and latency is under 2s
|
||||
// This is very useful for over the network playback that can't handle low latencies
|
||||
printf("underflow\n");
|
||||
// underflows++;
|
||||
/* if (underflows >= 6 && latency < 2000000) {
|
||||
latency = (latency*3)/2;
|
||||
bufattr.maxlength = pa_usec_to_bytes(latency,&ss);
|
||||
bufattr.tlength = pa_usec_to_bytes(latency,&ss);
|
||||
pa_stream_set_buffer_attr(s, &bufattr, NULL, NULL);
|
||||
underflows = 0;
|
||||
printf("latency increased to %d\n", latency);
|
||||
}*/
|
||||
}
|
||||
|
||||
|
||||
void pa_state_cb(pa_context *c, void *userdata) {
|
||||
pa_context_state_t state;
|
||||
int *pa_ready = userdata;
|
||||
state = pa_context_get_state(c);
|
||||
switch (state) {
|
||||
// These are just here for reference
|
||||
case PA_CONTEXT_UNCONNECTED:
|
||||
case PA_CONTEXT_CONNECTING:
|
||||
case PA_CONTEXT_AUTHORIZING:
|
||||
case PA_CONTEXT_SETTING_NAME:
|
||||
default:
|
||||
break;
|
||||
case PA_CONTEXT_FAILED:
|
||||
case PA_CONTEXT_TERMINATED:
|
||||
*pa_ready = 2;
|
||||
break;
|
||||
case PA_CONTEXT_READY:
|
||||
*pa_ready = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void * InitSoundPulse( SoundCBType cb )
|
||||
{
|
||||
static pa_buffer_attr bufattr;
|
||||
static pa_sample_spec ss;
|
||||
int error;
|
||||
pa_mainloop_api *pa_mlapi;
|
||||
struct SoundDriverPulse * r = malloc( sizeof( struct SoundDriverPulse ) );
|
||||
|
||||
r->pa_ml = pa_mainloop_new();
|
||||
pa_mlapi = pa_mainloop_get_api(r->pa_ml);
|
||||
const char * title = GetParameterS( "title", "PA Test" );
|
||||
r->pa_ctx = pa_context_new(pa_mlapi, title );
|
||||
pa_context_connect(r->pa_ctx, NULL, 0, NULL);
|
||||
|
||||
//TODO: pa_context_set_state_callback
|
||||
|
||||
r->CloseFn = CloseSoundPulse;
|
||||
r->SoundStateFn = SoundStatePulse;
|
||||
r->callback = cb;
|
||||
|
||||
r->spsPlay = GetParameterI( "samplerate", 44100 );
|
||||
r->channelsPlay = GetParameterI( "channels", 2 );
|
||||
r->spsRec = r->spsPlay;
|
||||
r->channelsRec = r->channelsPlay;
|
||||
r->sourceName = GetParameterS( "sourcename", NULL );
|
||||
|
||||
if( strcmp( r->sourceName, "default" ) == 0 )
|
||||
{
|
||||
r->sourceName = 0;
|
||||
}
|
||||
|
||||
r->play = 0;
|
||||
r->rec = 0;
|
||||
r->buffer = GetParameterI( "buffer", 1024 );
|
||||
printf ("Pulse: from: %s (%s) / %dx%d (%d)\n", r->sourceName, title, r->spsPlay, r->channelsPlay, r->buffer );
|
||||
|
||||
memset( &ss, 0, sizeof( ss ) );
|
||||
|
||||
ss.format = PA_SAMPLE_FLOAT32NE;
|
||||
ss.rate = r->spsPlay;
|
||||
ss.channels = r->channelsPlay;
|
||||
|
||||
r->pa_ready = 0;
|
||||
pa_context_set_state_callback(r->pa_ctx, pa_state_cb, &r->pa_ready);
|
||||
|
||||
while (r->pa_ready == 0)
|
||||
{
|
||||
pa_mainloop_iterate(r->pa_ml, 1, NULL);
|
||||
}
|
||||
|
||||
int bufbytes = r->buffer * sizeof(float) * r->channelsRec;
|
||||
|
||||
if( GetParameterI( "play", 1 ) )
|
||||
{
|
||||
if (!(r->play = pa_stream_new(r->pa_ctx, "Play", &ss, NULL))) {
|
||||
error = -3; //XXX ??? TODO
|
||||
fprintf(stderr, __FILE__": pa_simple_new() failed: %s\n", pa_strerror(error));
|
||||
goto fail;
|
||||
}
|
||||
|
||||
pa_stream_set_underflow_callback(r->play, stream_underflow_cb, NULL);
|
||||
pa_stream_set_write_callback(r->play, stream_request_cb, r );
|
||||
|
||||
bufattr.fragsize = (uint32_t)-1;
|
||||
bufattr.maxlength = bufbytes*3; //XXX TODO Consider making this -1
|
||||
bufattr.minreq = 0;
|
||||
bufattr.prebuf = (uint32_t)-1;
|
||||
bufattr.tlength = bufbytes*3;
|
||||
int ret = pa_stream_connect_playback(r->play, NULL, &bufattr,
|
||||
// PA_STREAM_INTERPOLATE_TIMING
|
||||
// |PA_STREAM_ADJUST_LATENCY //Some servers don't like the adjust_latency flag.
|
||||
// |PA_STREAM_AUTO_TIMING_UPDATE, NULL, NULL);
|
||||
0, NULL, NULL );
|
||||
printf( "Play stream.\n" );
|
||||
if( ret < 0 )
|
||||
{
|
||||
fprintf(stderr, __FILE__": (PLAY) pa_stream_connect_playback() failed: %s\n", pa_strerror(ret));
|
||||
goto fail;
|
||||
}
|
||||
}
|
||||
|
||||
if( GetParameterI( "rec", 1 ) )
|
||||
{
|
||||
if (!(r->rec = pa_stream_new(r->pa_ctx, "Record", &ss, NULL))) {
|
||||
error = -3; //XXX ??? TODO
|
||||
fprintf(stderr, __FILE__": pa_simple_new() failed: %s\n", pa_strerror(error));
|
||||
goto fail;
|
||||
}
|
||||
|
||||
pa_stream_set_read_callback(r->rec, stream_record_cb, r );
|
||||
|
||||
bufattr.fragsize = bufbytes;
|
||||
bufattr.maxlength = (uint32_t)-1;//(uint32_t)-1; //XXX: Todo, should this be low?
|
||||
bufattr.minreq = bufbytes;
|
||||
bufattr.prebuf = (uint32_t)-1;
|
||||
bufattr.tlength = bufbytes*3;
|
||||
printf( "Source: %s\n", r->sourceName );
|
||||
int ret = pa_stream_connect_record(r->rec, r->sourceName, &bufattr, 0
|
||||
// |PA_STREAM_INTERPOLATE_TIMING
|
||||
|PA_STREAM_ADJUST_LATENCY //Some servers don't like the adjust_latency flag.
|
||||
// |PA_STREAM_AUTO_TIMING_UPDATE
|
||||
// 0
|
||||
);
|
||||
|
||||
printf( "Got handle: %d\n", ret );
|
||||
if( ret < 0 )
|
||||
{
|
||||
fprintf(stderr, __FILE__": (REC) pa_stream_connect_playback() failed: %s\n", pa_strerror(ret));
|
||||
goto fail;
|
||||
}
|
||||
}
|
||||
|
||||
printf( "Pulse initialized.\n" );
|
||||
|
||||
|
||||
// SoundThread( r );
|
||||
r->thread = OGCreateThread( SoundThread, r );
|
||||
return r;
|
||||
|
||||
fail:
|
||||
if( r )
|
||||
{
|
||||
if( r->play ) pa_xfree (r->play);
|
||||
if( r->rec ) pa_xfree (r->rec);
|
||||
free( r );
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
REGISTER_SOUND( PulseSound, 11, "PULSE", InitSoundPulse );
|
||||
|
||||
|
|
@ -1,190 +0,0 @@
|
|||
//Copyright 2015 <>< Charles Lohr under the ColorChord License.
|
||||
|
||||
#include <windows.h>
|
||||
#include "parameters.h"
|
||||
#include "sound.h"
|
||||
#include "os_generic.h"
|
||||
#include <stdio.h>
|
||||
#include <stdint.h>
|
||||
#include <mmsystem.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#if defined(WIN32) && !defined( TCC )
|
||||
#pragma comment(lib,"winmm.lib")
|
||||
#endif
|
||||
|
||||
#define BUFFS 2
|
||||
|
||||
struct SoundDriverWin
|
||||
{
|
||||
void (*CloseFn)( struct SoundDriverWin * object );
|
||||
int (*SoundStateFn)( struct SoundDriverWin * object );
|
||||
SoundCBType callback;
|
||||
int channelsPlay;
|
||||
int spsPlay;
|
||||
int channelsRec;
|
||||
int spsRec;
|
||||
|
||||
|
||||
int buffer;
|
||||
int isEnding;
|
||||
int GOBUFF;
|
||||
|
||||
int recording;
|
||||
|
||||
HWAVEIN hMyWave;
|
||||
WAVEHDR WavBuff[BUFFS];
|
||||
};
|
||||
|
||||
static struct SoundDriverWin * w;
|
||||
|
||||
void CloseSoundWin( struct SoundDriverWin * r )
|
||||
{
|
||||
int i;
|
||||
|
||||
if( r )
|
||||
{
|
||||
waveInStop(r->hMyWave);
|
||||
waveInReset(r->hMyWave);
|
||||
|
||||
for ( i=0;i<BUFFS;i++)
|
||||
{
|
||||
waveInUnprepareHeader(r->hMyWave,&(r->WavBuff[i]),sizeof(WAVEHDR));
|
||||
free ((r->WavBuff[i]).lpData);
|
||||
}
|
||||
waveInClose(r->hMyWave);
|
||||
free( r );
|
||||
}
|
||||
}
|
||||
|
||||
int SoundStateWin( struct SoundDriverWin * soundobject )
|
||||
{
|
||||
return soundobject->recording;
|
||||
}
|
||||
|
||||
void CALLBACK HANDLEMIC(HWAVEIN hwi,UINT umsg, DWORD dwi, DWORD hdr, DWORD dwparm)
|
||||
{
|
||||
int ctr;
|
||||
int ob;
|
||||
long cValue;
|
||||
unsigned int maxWave=0;
|
||||
|
||||
float buffer[w->buffer*w->channelsRec];
|
||||
|
||||
if (w->isEnding) return;
|
||||
|
||||
switch (umsg)
|
||||
{
|
||||
case MM_WIM_OPEN:
|
||||
printf( "Mic Open.\n" );
|
||||
w->recording = 1;
|
||||
break;
|
||||
|
||||
case MM_WIM_DATA:
|
||||
// printf( "Mic Data.\n");
|
||||
ob = (w->GOBUFF+(BUFFS))%BUFFS;
|
||||
// waveInPrepareHeader(w->hMyWave,&(w->WavBuff[w->Cbuff]),sizeof(WAVEHDR));
|
||||
|
||||
for (ctr=0;ctr<w->buffer * w->channelsRec;ctr++) {
|
||||
float cv = (uint16_t)(((uint8_t)w->WavBuff[ob].lpData[ctr*2+1])*256+((uint8_t)w->WavBuff[ob].lpData[ctr*2])+32768)-32768;
|
||||
cv /= 32768;
|
||||
// if( ctr < 3 ) cv = -1;
|
||||
// buffer[(w->buffer * w->channelsRec)-ctr-1] = cv;
|
||||
buffer[ctr] = cv;
|
||||
}
|
||||
|
||||
waveInAddBuffer(w->hMyWave,&(w->WavBuff[w->GOBUFF]),sizeof(WAVEHDR));
|
||||
w->GOBUFF = ( w->GOBUFF + 1 ) % BUFFS;
|
||||
|
||||
int playbacksamples; //Unused
|
||||
w->callback( 0, buffer, w->buffer, &playbacksamples, (struct SoundDriver*)w );
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static struct SoundDriverWin * InitWinSound( struct SoundDriverWin * r )
|
||||
{
|
||||
int i;
|
||||
WAVEFORMATEX wfmt;
|
||||
memset( &wfmt, 0, sizeof(wfmt) );
|
||||
printf ("WFMT Size (debugging temp for TCC): %d\n", sizeof(wfmt) );
|
||||
if( GetParameterI( "play", 0 ) )
|
||||
{
|
||||
fprintf( stderr, "Error: This Windows Sound Driver does not support playback.\n" );
|
||||
exit( -1 );
|
||||
}
|
||||
|
||||
w = r;
|
||||
|
||||
|
||||
printf( "WFMT: %d %d %d\n", r->channelsRec, r->spsRec,
|
||||
r->spsRec * r->channelsRec );
|
||||
|
||||
wfmt.wFormatTag = WAVE_FORMAT_PCM;
|
||||
wfmt.nChannels = r->channelsRec;
|
||||
wfmt.nSamplesPerSec = r->spsRec;
|
||||
wfmt.nAvgBytesPerSec = r->spsRec * r->channelsRec;
|
||||
wfmt.nBlockAlign = r->channelsRec * 2;
|
||||
wfmt.wBitsPerSample = 16;
|
||||
wfmt.cbSize = 0;
|
||||
|
||||
long dwdevice;
|
||||
dwdevice = GetParameterI( "wininput", WAVE_MAPPER );
|
||||
|
||||
printf( "Wave Devs: %d; WAVE_MAPPER: %d; Selected Input: %d\n", waveInGetNumDevs(), WAVE_MAPPER, dwdevice );
|
||||
|
||||
printf( "waveInOpen: %p, %p\n", r->hMyWave, &wfmt );
|
||||
|
||||
int p = waveInOpen(&r->hMyWave, dwdevice, &wfmt, (void*)(&HANDLEMIC) , 0, CALLBACK_FUNCTION);
|
||||
|
||||
if( p )
|
||||
{
|
||||
fprintf( stderr, "Error performing waveInOpen. Received code: %d\n", p );
|
||||
}
|
||||
|
||||
for ( i=0;i<BUFFS;i++)
|
||||
{
|
||||
memset( &(r->WavBuff[i]), 0, sizeof(r->WavBuff[i]) );
|
||||
(r->WavBuff[i]).dwBufferLength = r->buffer*2*r->channelsRec;
|
||||
(r->WavBuff[i]).dwLoops = 1;
|
||||
(r->WavBuff[i]).lpData=(char*) malloc(r->buffer*r->channelsRec*2);
|
||||
p = waveInPrepareHeader(r->hMyWave,&(r->WavBuff[i]),sizeof(WAVEHDR));
|
||||
printf( "WIP: %d\n", p );
|
||||
waveInAddBuffer(r->hMyWave,&(r->WavBuff[i]),sizeof(WAVEHDR));
|
||||
printf( "WIA: %d\n", p );
|
||||
}
|
||||
\
|
||||
p = waveInStart(r->hMyWave);
|
||||
if( p )
|
||||
{
|
||||
fprintf( stderr, "Error performing waveInStart. Received code %d\n", p );
|
||||
}
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void * InitSoundWin( SoundCBType cb )
|
||||
{
|
||||
struct SoundDriverWin * r = (struct SoundDriverWin *)malloc( sizeof( struct SoundDriverWin ) );
|
||||
|
||||
r->CloseFn = CloseSoundWin;
|
||||
r->SoundStateFn = SoundStateWin;
|
||||
r->callback = cb;
|
||||
|
||||
r->spsRec = GetParameterI( "samplerate", 44100 );
|
||||
r->channelsRec = GetParameterI( "channels", 2 );
|
||||
r->buffer = GetParameterI( "buffer", 384 );
|
||||
r->recording = 0;
|
||||
r->isEnding = 0;
|
||||
printf( "Buffer: %d\n", r->buffer );
|
||||
|
||||
r->GOBUFF=0;
|
||||
|
||||
return InitWinSound(r);
|
||||
}
|
||||
|
||||
REGISTER_SOUND( SoundWin, 10, "WIN", InitSoundWin );
|
||||
|
Loading…
Reference in a new issue