Rearchitect colorchord using CNFA + Rawdraw modules.

This commit is contained in:
cnlohr 2020-05-10 17:15:59 -07:00
parent e243c7200b
commit 3d922b514c
16 changed files with 93 additions and 1445 deletions

3
.gitmodules vendored
View file

@ -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

View file

@ -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)

View file

@ -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

@ -0,0 +1 @@
Subproject commit 22f0e58a4df57c6a6b5fa05665a6d454e597e2da

Binary file not shown.

View file

@ -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++ )

View file

@ -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

View file

@ -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

View file

@ -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 );
}
}

View file

@ -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

View file

@ -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 );

View file

@ -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 );

View file

@ -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 );

View file

@ -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 );

View file

@ -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 );