changeset 15:19ff95c69cf5

moved send.c to org file
author Robert McIntyre <rlm@mit.edu>
date Thu, 03 Nov 2011 12:08:39 -0700
parents 63312ec4a2bf
children 3de8325e79bf
files .hgignore Alc/backends/send.c org/ear.org
diffstat 3 files changed, 621 insertions(+), 44 deletions(-) [+]
line wrap: on
line diff
     1.1 --- a/.hgignore	Mon Oct 31 08:01:08 2011 -0700
     1.2 +++ b/.hgignore	Thu Nov 03 12:08:39 2011 -0700
     1.3 @@ -6,4 +6,5 @@
     1.4  java/bin*
     1.5  java/dist*
     1.6  java/build/*
     1.7 -java/headers/*
     1.8 \ No newline at end of file
     1.9 +java/headers/*
    1.10 +Alc/backends/send.c
    1.11 \ No newline at end of file
     2.1 --- a/Alc/backends/send.c	Mon Oct 31 08:01:08 2011 -0700
     2.2 +++ b/Alc/backends/send.c	Thu Nov 03 12:08:39 2011 -0700
     2.3 @@ -1,3 +1,4 @@
     2.4 +
     2.5  #include "config.h"
     2.6  #include <stdlib.h>
     2.7  #include "alMain.h"
     2.8 @@ -304,15 +305,13 @@
     2.9    ALCdevice *recorder = (ALCdevice*) ((intptr_t)device);
    2.10    send_data *data = (send_data*)recorder->ExtraData;
    2.11    if ((ALuint)n > data->numContexts){return;}
    2.12 -  //if ((uint) samples > data->size){
    2.13 -  //  samples = (int) data->size;
    2.14 -  //}
    2.15 -  printf("Want %d samples for listener %d\n", samples, n);
    2.16 -  printf("Device's format type is %d bytes per sample,\n", 
    2.17 -	  BytesFromDevFmt(recorder->FmtType));
    2.18 -  printf("and it has %d channels, making for %d requested bytes\n", 
    2.19 -	 recorder->NumChan, 
    2.20 -	 BytesFromDevFmt(recorder->FmtType) * recorder->NumChan * samples);
    2.21 +  
    2.22 +  //printf("Want %d samples for listener %d\n", samples, n);
    2.23 +  //printf("Device's format type is %d bytes per sample,\n", 
    2.24 +  //  BytesFromDevFmt(recorder->FmtType));
    2.25 +  //printf("and it has %d channels, making for %d requested bytes\n", 
    2.26 +  //	 recorder->NumChan, 
    2.27 +  //	 BytesFromDevFmt(recorder->FmtType) * recorder->NumChan * samples);
    2.28  
    2.29    memcpy(buffer_address, data->contexts[n]->renderBuffer, 
    2.30  	 BytesFromDevFmt(recorder->FmtType) * recorder->NumChan * samples);
    2.31 @@ -327,7 +326,7 @@
    2.32  JNIEXPORT void JNICALL Java_com_aurellem_send_AudioSend_naddListener
    2.33  (JNIEnv *env, jclass clazz, jlong device){
    2.34    UNUSED(env); UNUSED(clazz);
    2.35 -  printf("creating new context via naddListener\n");
    2.36 +  //printf("creating new context via naddListener\n");
    2.37    ALCdevice *Device = (ALCdevice*) ((intptr_t)device);
    2.38    ALCcontext *new = alcCreateContext(Device, NULL);
    2.39    addContext(Device, new);
    2.40 @@ -418,8 +417,8 @@
    2.41    int channels = Device->NumChan;
    2.42  
    2.43  
    2.44 -  printf("freq = %f, bpf = %d, channels = %d, signed? = %d\n",
    2.45 -	 frequency, bitsPerFrame, channels, isSigned);
    2.46 +  //printf("freq = %f, bpf = %d, channels = %d, signed? = %d\n",
    2.47 +  //	 frequency, bitsPerFrame, channels, isSigned);
    2.48  
    2.49    jobject format = (*env)->
    2.50      NewObject(
    2.51 @@ -517,6 +516,3 @@
    2.52        break;
    2.53      }
    2.54  }
    2.55 -
    2.56 -
    2.57 -
     3.1 --- a/org/ear.org	Mon Oct 31 08:01:08 2011 -0700
     3.2 +++ b/org/ear.org	Thu Nov 03 12:08:39 2011 -0700
     3.3 @@ -1,25 +1,617 @@
     3.4 -#+title: The EARS!
     3.5 +#+title: Simulated Sense of Hearing
     3.6  #+author: Robert McIntyre
     3.7  #+email: rlm@mit.edu
     3.8 -#+MATHJAX: align:"left" mathml:t path:"../aurellem/src/MathJax/MathJax.js"
     3.9 -#+STYLE: <link rel="stylesheet" type="text/css" href="../aurellem/src/css/aurellem.css"/>
    3.10 +#+description: Simulating multiple listeners and the sense of hearing in jMonkeyEngine3
    3.11 +#+keywords: simulated hearing, openal, clojure, jMonkeyEngine3, LWJGL, AI
    3.12 +#+SETUPFILE: ../../aurellem/org/setup.org
    3.13 +#+INCLUDE: ../../aurellem/org/level-0.org
    3.14  #+BABEL: :exports both :noweb yes :cache no :mkdirp yes
    3.15 -#+INCLUDE: ../aurellem/src/templates/level-0.org
    3.16 -#+description: Simulating multiple listeners and the sense of hearing in uMonkeyEngine3
    3.17  
    3.18  
    3.19  
    3.20  
    3.21 -* Ears!
    3.22 +* Hearing
    3.23  
    3.24  I want to be able to place ears in a similiar manner to how I place
    3.25  the eyes.  I want to be able to place ears in a unique spatial
    3.26  position, and recieve as output at every tick the FFT of whatever
    3.27  signals are happening at that point.
    3.28  
    3.29 -#+srcname: ear-header
    3.30 +Hearing is one of the more difficult senses to simulate, because there
    3.31 +is less support for obtaining the actual sound data that is processed
    3.32 +by jMonkeyEngine3.
    3.33 +
    3.34 +jMonkeyEngine's sound system works as follows:
    3.35 +
    3.36 + - jMonkeyEngine uese the =AppSettings= for the particular application
    3.37 +   to determine what sort of =AudioRenderer= should be used.
    3.38 + - although some support is provided for multiple AudioRendering
    3.39 +   backends, jMonkeyEngine at the time of this writing will either
    3.40 +   pick no AudioRender at all, or the =LwjglAudioRenderer=
    3.41 + - jMonkeyEngine tries to figure out what sort of system you're
    3.42 +   running and extracts the appropiate native libraries.
    3.43 + - the =LwjglAudioRenderer= uses the [[http://lwjgl.org/][=LWJGL=]] (lightweight java game
    3.44 +   library) bindings to interface with a C library called [[http://kcat.strangesoft.net/openal.html][=OpenAL=]]
    3.45 + - =OpenAL= calculates the 3D sound localization and feeds a stream of
    3.46 +   sound to any of various sound output devices with which it knows
    3.47 +   how to communicate.
    3.48 +
    3.49 +A consequence of this is that there's no way to access the actual
    3.50 +sound data produced by =OpenAL=.  Even worse, =OpanAL= only supports
    3.51 +one /listener/, which normally isn't a problem for games, but becomes
    3.52 +a problem when trying to make multiple AI creatures that can each hear
    3.53 +the world from a different perspective.
    3.54 +
    3.55 +To make many AI creatures in jMonkeyEngine that can each hear the
    3.56 +world from their own perspective, it is necessary to go all the way
    3.57 +back to =OpenAL= and implement support for simulated hearing there.
    3.58 +
    3.59 +** =OpenAL= Devices
    3.60 +   
    3.61 +=OpenAL= goes to great lengths to support many different systems, all
    3.62 +with different sound capabilities and interfaces.  It acomplishes this
    3.63 +difficult task by providing code for many different sound backends in
    3.64 +pseudo-objects called /Devices/.  There's a device for the Linux Open
    3.65 +Sound System and the Advanced Linxu Sound Architechture, there's one
    3.66 +for Direct Sound on Windows, there's even one for Solaris. =OpenAL=
    3.67 +solves the problem of platform independence by providing all these
    3.68 +Devices.
    3.69 +
    3.70 +Wrapper libraries such as LWJGL are free to examine the system on
    3.71 +which they are running and then select an appropiate device for that
    3.72 +system. 
    3.73 +
    3.74 +There are also a few "special" devices that don't interface with any
    3.75 +particular system.  These include the Null Device, which doesn't do
    3.76 +anything, and the Wave Device, which writes whatever sound it recieves
    3.77 +to a file, if everything has been set up correctly when configuring
    3.78 +=OpenAL=.
    3.79 +
    3.80 +Actual mixing of the sound data happens in the Devices, and they are
    3.81 +the only point in the sound rendering process where this data is
    3.82 +available. 
    3.83 +
    3.84 +Therefore, in order to support multiple listeners, and get the sound
    3.85 +data in a form that the AIs can use, it is necessary to create a new
    3.86 +Device, which supports this features.
    3.87 +
    3.88 +
    3.89 +** The Send Device
    3.90 +Adding a device to OpenAL is rather tricky -- there are five separate
    3.91 +files in the =OpenAL= source tree that must be modified to do so. I've
    3.92 +documented this process [[./add-new-device.org][here]] for anyone who is interested.
    3.93 +
    3.94 +#+srcname: send
    3.95 +#+begin_src C
    3.96 +#include "config.h"
    3.97 +#include <stdlib.h>
    3.98 +#include "alMain.h"
    3.99 +#include "AL/al.h"
   3.100 +#include "AL/alc.h"
   3.101 +#include "alSource.h"
   3.102 +#include <jni.h>
   3.103 +
   3.104 +//////////////////// Summary
   3.105 +
   3.106 +struct send_data;
   3.107 +struct context_data;
   3.108 +
   3.109 +static void addContext(ALCdevice *, ALCcontext *);
   3.110 +static void syncContexts(ALCcontext *master, ALCcontext *slave);
   3.111 +static void syncSources(ALsource *master, ALsource *slave, 
   3.112 +			ALCcontext *masterCtx, ALCcontext *slaveCtx);
   3.113 +
   3.114 +static void syncSourcei(ALuint master, ALuint slave,
   3.115 +			ALCcontext *masterCtx, ALCcontext *ctx2, ALenum param);
   3.116 +static void syncSourcef(ALuint master, ALuint slave,
   3.117 +			ALCcontext *masterCtx, ALCcontext *ctx2, ALenum param);
   3.118 +static void syncSource3f(ALuint master, ALuint slave,
   3.119 +			ALCcontext *masterCtx, ALCcontext *ctx2, ALenum param);
   3.120 +
   3.121 +static void swapInContext(ALCdevice *, struct context_data *);
   3.122 +static void saveContext(ALCdevice *, struct context_data *);
   3.123 +static void limitContext(ALCdevice *, ALCcontext *);
   3.124 +static void unLimitContext(ALCdevice *);
   3.125 +
   3.126 +static void init(ALCdevice *);
   3.127 +static void renderData(ALCdevice *, int samples);
   3.128 +
   3.129 +#define UNUSED(x)  (void)(x)
   3.130 +
   3.131 +////////////////////  State
   3.132 +
   3.133 +typedef struct context_data {
   3.134 +  ALfloat ClickRemoval[MAXCHANNELS];
   3.135 +  ALfloat PendingClicks[MAXCHANNELS];
   3.136 +  ALvoid *renderBuffer;
   3.137 +  ALCcontext *ctx;
   3.138 +} context_data;
   3.139 +
   3.140 +typedef struct send_data {
   3.141 +  ALuint size;
   3.142 +  context_data **contexts;
   3.143 +  ALuint numContexts;
   3.144 +  ALuint maxContexts;
   3.145 +} send_data;
   3.146 +
   3.147 +
   3.148 +
   3.149 +////////////////////  Context Creation / Synchronization
   3.150 +
   3.151 +#define _MAKE_SYNC(NAME, INIT_EXPR, GET_EXPR, SET_EXPR)	\
   3.152 +  void NAME (ALuint sourceID1, ALuint sourceID2,	\
   3.153 +	     ALCcontext *ctx1, ALCcontext *ctx2,	\
   3.154 +	     ALenum param){				\
   3.155 +    INIT_EXPR;						\
   3.156 +    ALCcontext *current = alcGetCurrentContext();	\
   3.157 +    alcMakeContextCurrent(ctx1);			\
   3.158 +    GET_EXPR;						\
   3.159 +    alcMakeContextCurrent(ctx2);			\
   3.160 +    SET_EXPR;						\
   3.161 +    alcMakeContextCurrent(current);			\
   3.162 +  }
   3.163 +  
   3.164 +#define MAKE_SYNC(NAME, TYPE, GET, SET)			\
   3.165 +  _MAKE_SYNC(NAME,					\
   3.166 +	     TYPE value,				\
   3.167 +             GET(sourceID1, param, &value),		\
   3.168 +             SET(sourceID2, param, value))
   3.169 +  
   3.170 +#define MAKE_SYNC3(NAME, TYPE, GET, SET)				\
   3.171 +  _MAKE_SYNC(NAME,							\
   3.172 +	     TYPE value1; TYPE value2; TYPE value3;,			\
   3.173 +	     GET(sourceID1, param, &value1, &value2, &value3),		\
   3.174 +	     SET(sourceID2, param,  value1,  value2,  value3))
   3.175 +
   3.176 +MAKE_SYNC( syncSourcei,  ALint,   alGetSourcei,  alSourcei);
   3.177 +MAKE_SYNC( syncSourcef,  ALfloat, alGetSourcef,  alSourcef);
   3.178 +MAKE_SYNC3(syncSource3i, ALint,   alGetSource3i, alSource3i);
   3.179 +MAKE_SYNC3(syncSource3f, ALfloat, alGetSource3f, alSource3f);
   3.180 +  
   3.181 +void syncSources(ALsource *masterSource, ALsource *slaveSource, 
   3.182 +		 ALCcontext *masterCtx, ALCcontext *slaveCtx){
   3.183 +  ALuint master = masterSource->source;
   3.184 +  ALuint slave = slaveSource->source;
   3.185 +  ALCcontext *current = alcGetCurrentContext();
   3.186 +
   3.187 +  syncSourcef(master,slave,masterCtx,slaveCtx,AL_PITCH);
   3.188 +  syncSourcef(master,slave,masterCtx,slaveCtx,AL_GAIN);
   3.189 +  syncSourcef(master,slave,masterCtx,slaveCtx,AL_MAX_DISTANCE);
   3.190 +  syncSourcef(master,slave,masterCtx,slaveCtx,AL_ROLLOFF_FACTOR);
   3.191 +  syncSourcef(master,slave,masterCtx,slaveCtx,AL_REFERENCE_DISTANCE);
   3.192 +  syncSourcef(master,slave,masterCtx,slaveCtx,AL_MIN_GAIN);
   3.193 +  syncSourcef(master,slave,masterCtx,slaveCtx,AL_MAX_GAIN);
   3.194 +  syncSourcef(master,slave,masterCtx,slaveCtx,AL_CONE_OUTER_GAIN);
   3.195 +  syncSourcef(master,slave,masterCtx,slaveCtx,AL_CONE_INNER_ANGLE);
   3.196 +  syncSourcef(master,slave,masterCtx,slaveCtx,AL_CONE_OUTER_ANGLE);
   3.197 +  syncSourcef(master,slave,masterCtx,slaveCtx,AL_SEC_OFFSET);
   3.198 +  syncSourcef(master,slave,masterCtx,slaveCtx,AL_SAMPLE_OFFSET);
   3.199 +  syncSourcef(master,slave,masterCtx,slaveCtx,AL_BYTE_OFFSET);
   3.200 +    
   3.201 +  syncSource3f(master,slave,masterCtx,slaveCtx,AL_POSITION);
   3.202 +  syncSource3f(master,slave,masterCtx,slaveCtx,AL_VELOCITY);
   3.203 +  syncSource3f(master,slave,masterCtx,slaveCtx,AL_DIRECTION);
   3.204 +  
   3.205 +  syncSourcei(master,slave,masterCtx,slaveCtx,AL_SOURCE_RELATIVE);
   3.206 +  syncSourcei(master,slave,masterCtx,slaveCtx,AL_LOOPING);
   3.207 +
   3.208 +  alcMakeContextCurrent(masterCtx);
   3.209 +  ALint source_type;
   3.210 +  alGetSourcei(master, AL_SOURCE_TYPE, &source_type);
   3.211 +
   3.212 +  // Only static sources are currently synchronized! 
   3.213 +  if (AL_STATIC == source_type){
   3.214 +    ALint master_buffer;
   3.215 +    ALint slave_buffer;
   3.216 +    alGetSourcei(master, AL_BUFFER, &master_buffer);
   3.217 +    alcMakeContextCurrent(slaveCtx);
   3.218 +    alGetSourcei(slave, AL_BUFFER, &slave_buffer);
   3.219 +    if (master_buffer != slave_buffer){
   3.220 +      alSourcei(slave, AL_BUFFER, master_buffer);
   3.221 +    }
   3.222 +  }
   3.223 +  
   3.224 +  // Synchronize the state of the two sources.
   3.225 +  alcMakeContextCurrent(masterCtx);
   3.226 +  ALint masterState;
   3.227 +  ALint slaveState;
   3.228 +
   3.229 +  alGetSourcei(master, AL_SOURCE_STATE, &masterState);
   3.230 +  alcMakeContextCurrent(slaveCtx);
   3.231 +  alGetSourcei(slave, AL_SOURCE_STATE, &slaveState);
   3.232 +
   3.233 +  if (masterState != slaveState){
   3.234 +    switch (masterState){
   3.235 +    case AL_INITIAL : alSourceRewind(slave); break;
   3.236 +    case AL_PLAYING : alSourcePlay(slave);   break;
   3.237 +    case AL_PAUSED  : alSourcePause(slave);  break;
   3.238 +    case AL_STOPPED : alSourceStop(slave);   break;
   3.239 +    }
   3.240 +  }
   3.241 +  // Restore whatever context was previously active.
   3.242 +  alcMakeContextCurrent(current);
   3.243 +}
   3.244 +
   3.245 +
   3.246 +void syncContexts(ALCcontext *master, ALCcontext *slave){
   3.247 +  /* If there aren't sufficient sources in slave to mirror 
   3.248 +     the sources in master, create them. */
   3.249 +  ALCcontext *current = alcGetCurrentContext();
   3.250 +
   3.251 +  UIntMap *masterSourceMap = &(master->SourceMap);
   3.252 +  UIntMap *slaveSourceMap = &(slave->SourceMap);
   3.253 +  ALuint numMasterSources = masterSourceMap->size;
   3.254 +  ALuint numSlaveSources = slaveSourceMap->size;
   3.255 +
   3.256 +  alcMakeContextCurrent(slave);
   3.257 +  if (numSlaveSources < numMasterSources){
   3.258 +    ALuint numMissingSources = numMasterSources - numSlaveSources;
   3.259 +    ALuint newSources[numMissingSources];
   3.260 +    alGenSources(numMissingSources, newSources);
   3.261 +  }
   3.262 +
   3.263 +  /* Now, slave is gauranteed to have at least as many sources
   3.264 +     as master.  Sync each source from master to the corresponding
   3.265 +     source in slave. */
   3.266 +  int i;
   3.267 +  for(i = 0; i < masterSourceMap->size; i++){
   3.268 +    syncSources((ALsource*)masterSourceMap->array[i].value,
   3.269 +		(ALsource*)slaveSourceMap->array[i].value,
   3.270 +		master, slave);
   3.271 +  }
   3.272 +  alcMakeContextCurrent(current);
   3.273 +}
   3.274 +
   3.275 +static void addContext(ALCdevice *Device, ALCcontext *context){
   3.276 +  send_data *data = (send_data*)Device->ExtraData;
   3.277 +  // expand array if necessary
   3.278 +  if (data->numContexts >= data->maxContexts){
   3.279 +    ALuint newMaxContexts = data->maxContexts*2 + 1;
   3.280 +    data->contexts = realloc(data->contexts, newMaxContexts*sizeof(context_data));
   3.281 +    data->maxContexts = newMaxContexts;
   3.282 +  }
   3.283 +  // create context_data and add it to the main array
   3.284 +  context_data *ctxData;
   3.285 +  ctxData = (context_data*)calloc(1, sizeof(*ctxData));
   3.286 +  ctxData->renderBuffer = 
   3.287 +    malloc(BytesFromDevFmt(Device->FmtType) * 
   3.288 +	   Device->NumChan * Device->UpdateSize);
   3.289 +  ctxData->ctx = context;
   3.290 +
   3.291 +  data->contexts[data->numContexts] = ctxData;
   3.292 +  data->numContexts++;
   3.293 +}
   3.294 +
   3.295 +
   3.296 +////////////////////  Context Switching 
   3.297 +
   3.298 +/* A device brings along with it two pieces of state
   3.299 + * which have to be swapped in and out with each context.
   3.300 + */
   3.301 +static void swapInContext(ALCdevice *Device, context_data *ctxData){
   3.302 +  memcpy(Device->ClickRemoval, ctxData->ClickRemoval, sizeof(ALfloat)*MAXCHANNELS);
   3.303 +  memcpy(Device->PendingClicks, ctxData->PendingClicks, sizeof(ALfloat)*MAXCHANNELS);
   3.304 +}
   3.305 +
   3.306 +static void saveContext(ALCdevice *Device, context_data *ctxData){
   3.307 +  memcpy(ctxData->ClickRemoval, Device->ClickRemoval, sizeof(ALfloat)*MAXCHANNELS);
   3.308 +  memcpy(ctxData->PendingClicks, Device->PendingClicks, sizeof(ALfloat)*MAXCHANNELS);
   3.309 +}  
   3.310 +
   3.311 +static ALCcontext **currentContext;
   3.312 +static ALuint currentNumContext;
   3.313 +
   3.314 +/* By default, all contexts are rendered at once for each call to aluMixData.
   3.315 + * This function uses the internals of the ALCdecice struct to temporarly 
   3.316 + * cause aluMixData to only render the chosen context.
   3.317 + */
   3.318 +static void limitContext(ALCdevice *Device, ALCcontext *ctx){
   3.319 +  currentContext  = Device->Contexts;
   3.320 +  currentNumContext  = Device->NumContexts;
   3.321 +  Device->Contexts = &ctx;
   3.322 +  Device->NumContexts = 1;
   3.323 +}
   3.324 +
   3.325 +static void unLimitContext(ALCdevice *Device){
   3.326 +  Device->Contexts = currentContext;
   3.327 +  Device->NumContexts = currentNumContext;
   3.328 +}
   3.329 +
   3.330 +
   3.331 +////////////////////   Main Device Loop
   3.332 +
   3.333 +/* Establish the LWJGL context as the main context, which will
   3.334 + * be synchronized to all the slave contexts
   3.335 + */
   3.336 +static void init(ALCdevice *Device){
   3.337 +  ALCcontext *masterContext = alcGetCurrentContext();
   3.338 +  addContext(Device, masterContext);
   3.339 +}
   3.340 +
   3.341 +
   3.342 +static void renderData(ALCdevice *Device, int samples){
   3.343 +  if(!Device->Connected){return;}
   3.344 +  send_data *data = (send_data*)Device->ExtraData;
   3.345 +  ALCcontext *current = alcGetCurrentContext();
   3.346 +
   3.347 +  ALuint i;
   3.348 +  for (i = 1; i < data->numContexts; i++){
   3.349 +    syncContexts(data->contexts[0]->ctx , data->contexts[i]->ctx);
   3.350 +  }
   3.351 +  
   3.352 +  if ((uint) samples > Device->UpdateSize){
   3.353 +    printf("exceeding internal buffer size; dropping samples\n");
   3.354 +    printf("requested %d; available %d\n", samples, Device->UpdateSize);
   3.355 +    samples = (int) Device->UpdateSize;
   3.356 +  }
   3.357 +
   3.358 +  for (i = 0; i < data->numContexts; i++){
   3.359 +    context_data *ctxData = data->contexts[i];
   3.360 +    ALCcontext *ctx = ctxData->ctx;
   3.361 +    alcMakeContextCurrent(ctx);
   3.362 +    limitContext(Device, ctx);
   3.363 +    swapInContext(Device, ctxData);
   3.364 +    aluMixData(Device, ctxData->renderBuffer, samples);
   3.365 +    saveContext(Device, ctxData);
   3.366 +    unLimitContext(Device);
   3.367 +  }
   3.368 +  alcMakeContextCurrent(current);
   3.369 +}
   3.370 +
   3.371 +
   3.372 +////////////////////   JNI Methods
   3.373 +
   3.374 +#include "com_aurellem_send_AudioSend.h"
   3.375 +
   3.376 +/*
   3.377 + * Class:     com_aurellem_send_AudioSend
   3.378 + * Method:    nstep
   3.379 + * Signature: (JI)V
   3.380 + */
   3.381 +JNIEXPORT void JNICALL Java_com_aurellem_send_AudioSend_nstep
   3.382 +(JNIEnv *env, jclass clazz, jlong device, jint samples){
   3.383 +  UNUSED(env);UNUSED(clazz);UNUSED(device);
   3.384 +  renderData((ALCdevice*)((intptr_t)device), samples);
   3.385 +}
   3.386 +
   3.387 +/*
   3.388 + * Class:     com_aurellem_send_AudioSend
   3.389 + * Method:    ngetSamples
   3.390 + * Signature: (JLjava/nio/ByteBuffer;III)V
   3.391 + */
   3.392 +JNIEXPORT void JNICALL Java_com_aurellem_send_AudioSend_ngetSamples
   3.393 +(JNIEnv *env, jclass clazz, jlong device, jobject buffer, jint position, 
   3.394 + jint samples, jint n){
   3.395 +  UNUSED(clazz);  
   3.396 +
   3.397 +  ALvoid *buffer_address = 
   3.398 +    ((ALbyte *)(((char*)(*env)->GetDirectBufferAddress(env, buffer)) + position));
   3.399 +  ALCdevice *recorder = (ALCdevice*) ((intptr_t)device);
   3.400 +  send_data *data = (send_data*)recorder->ExtraData;
   3.401 +  if ((ALuint)n > data->numContexts){return;}
   3.402 +  
   3.403 +  //printf("Want %d samples for listener %d\n", samples, n);
   3.404 +  //printf("Device's format type is %d bytes per sample,\n", 
   3.405 +  //  BytesFromDevFmt(recorder->FmtType));
   3.406 +  //printf("and it has %d channels, making for %d requested bytes\n", 
   3.407 +  //	 recorder->NumChan, 
   3.408 +  //	 BytesFromDevFmt(recorder->FmtType) * recorder->NumChan * samples);
   3.409 +
   3.410 +  memcpy(buffer_address, data->contexts[n]->renderBuffer, 
   3.411 +	 BytesFromDevFmt(recorder->FmtType) * recorder->NumChan * samples);
   3.412 +  //samples*sizeof(ALfloat));
   3.413 +}
   3.414 +
   3.415 +/*
   3.416 + * Class:     com_aurellem_send_AudioSend
   3.417 + * Method:    naddListener
   3.418 + * Signature: (J)V
   3.419 + */
   3.420 +JNIEXPORT void JNICALL Java_com_aurellem_send_AudioSend_naddListener
   3.421 +(JNIEnv *env, jclass clazz, jlong device){
   3.422 +  UNUSED(env); UNUSED(clazz);
   3.423 +  //printf("creating new context via naddListener\n");
   3.424 +  ALCdevice *Device = (ALCdevice*) ((intptr_t)device);
   3.425 +  ALCcontext *new = alcCreateContext(Device, NULL);
   3.426 +  addContext(Device, new);
   3.427 +}
   3.428 +
   3.429 +/*
   3.430 + * Class:     com_aurellem_send_AudioSend
   3.431 + * Method:    nsetNthListener3f
   3.432 + * Signature: (IFFFJI)V
   3.433 + */
   3.434 +JNIEXPORT void JNICALL Java_com_aurellem_send_AudioSend_nsetNthListener3f
   3.435 +  (JNIEnv *env, jclass clazz, jint param, 
   3.436 +   jfloat v1, jfloat v2, jfloat v3, jlong device, jint contextNum){
   3.437 +  UNUSED(env);UNUSED(clazz);
   3.438 +
   3.439 +  ALCdevice *Device = (ALCdevice*) ((intptr_t)device);
   3.440 +  send_data *data = (send_data*)Device->ExtraData;
   3.441 +  
   3.442 +  ALCcontext *current = alcGetCurrentContext();
   3.443 +  if ((ALuint)contextNum > data->numContexts){return;}
   3.444 +  alcMakeContextCurrent(data->contexts[contextNum]->ctx);
   3.445 +  alListener3f(param, v1, v2, v3);
   3.446 +  alcMakeContextCurrent(current);
   3.447 +}
   3.448 +
   3.449 +/*
   3.450 + * Class:     com_aurellem_send_AudioSend
   3.451 + * Method:    nsetNthListenerf
   3.452 + * Signature: (IFJI)V
   3.453 + */
   3.454 +JNIEXPORT void JNICALL Java_com_aurellem_send_AudioSend_nsetNthListenerf
   3.455 +(JNIEnv *env, jclass clazz, jint param, jfloat v1, jlong device, 
   3.456 + jint contextNum){
   3.457 +
   3.458 +  UNUSED(env);UNUSED(clazz);
   3.459 +  
   3.460 +  ALCdevice *Device = (ALCdevice*) ((intptr_t)device);
   3.461 +  send_data *data = (send_data*)Device->ExtraData;
   3.462 +  
   3.463 +  ALCcontext *current = alcGetCurrentContext();
   3.464 +  if ((ALuint)contextNum > data->numContexts){return;}
   3.465 +  alcMakeContextCurrent(data->contexts[contextNum]->ctx);
   3.466 +  alListenerf(param, v1);
   3.467 +  alcMakeContextCurrent(current);
   3.468 +}
   3.469 +
   3.470 +/*
   3.471 + * Class:     com_aurellem_send_AudioSend
   3.472 + * Method:    ninitDevice
   3.473 + * Signature: (J)V
   3.474 + */                     
   3.475 +JNIEXPORT void JNICALL Java_com_aurellem_send_AudioSend_ninitDevice
   3.476 +(JNIEnv *env, jclass clazz, jlong device){
   3.477 +  UNUSED(env);UNUSED(clazz);
   3.478 +  
   3.479 +  ALCdevice *Device = (ALCdevice*) ((intptr_t)device);
   3.480 +  init(Device);
   3.481 +
   3.482 +}
   3.483 +
   3.484 +
   3.485 +/*
   3.486 + * Class:     com_aurellem_send_AudioSend
   3.487 + * Method:    ngetAudioFormat
   3.488 + * Signature: (J)Ljavax/sound/sampled/AudioFormat;
   3.489 + */
   3.490 +JNIEXPORT jobject JNICALL Java_com_aurellem_send_AudioSend_ngetAudioFormat
   3.491 +(JNIEnv *env, jclass clazz, jlong device){
   3.492 +  UNUSED(clazz);
   3.493 +  jclass AudioFormatClass = 
   3.494 +    (*env)->FindClass(env, "javax/sound/sampled/AudioFormat");
   3.495 +  jmethodID AudioFormatConstructor = 
   3.496 +    (*env)->GetMethodID(env, AudioFormatClass, "<init>", "(FIIZZ)V");
   3.497 +  
   3.498 +  ALCdevice *Device = (ALCdevice*) ((intptr_t)device);
   3.499 +
   3.500 +  //float frequency
   3.501 +
   3.502 +  int isSigned;
   3.503 +  switch (Device->FmtType)
   3.504 +    {
   3.505 +    case DevFmtUByte: 
   3.506 +    case DevFmtUShort: isSigned = 0; break;  
   3.507 +    default : isSigned = 1;   
   3.508 +    }
   3.509 +  float frequency = Device->Frequency;
   3.510 +  int bitsPerFrame = (8 * BytesFromDevFmt(Device->FmtType));
   3.511 +  int channels = Device->NumChan;
   3.512 +
   3.513 +
   3.514 +  //printf("freq = %f, bpf = %d, channels = %d, signed? = %d\n",
   3.515 +  //	 frequency, bitsPerFrame, channels, isSigned);
   3.516 +
   3.517 +  jobject format = (*env)->
   3.518 +    NewObject(
   3.519 +	      env,AudioFormatClass,AudioFormatConstructor,
   3.520 +	      frequency,
   3.521 +	      bitsPerFrame,
   3.522 +	      channels,
   3.523 +	      isSigned,
   3.524 +	      0);
   3.525 +  return format;
   3.526 +}
   3.527 +
   3.528 +
   3.529 +
   3.530 +////////////////////   Device Initilization / Management
   3.531 +
   3.532 +static const ALCchar sendDevice[] = "Multiple Audio Send";
   3.533 +
   3.534 +static ALCboolean send_open_playback(ALCdevice *device, 
   3.535 + const ALCchar *deviceName)
   3.536 +{
   3.537 +  send_data *data;
   3.538 +  // stop any buffering for stdout, so that I can 
   3.539 +  // see the printf statements in my terminal immediatley
   3.540 +  setbuf(stdout, NULL);
   3.541 +
   3.542 +  if(!deviceName)
   3.543 +    deviceName = sendDevice;
   3.544 +  else if(strcmp(deviceName, sendDevice) != 0)
   3.545 +    return ALC_FALSE;
   3.546 +  data = (send_data*)calloc(1, sizeof(*data));
   3.547 +  device->szDeviceName = strdup(deviceName);
   3.548 +  device->ExtraData = data;
   3.549 +  return ALC_TRUE;
   3.550 +}
   3.551 +
   3.552 +static void send_close_playback(ALCdevice *device)
   3.553 +{
   3.554 +  send_data *data = (send_data*)device->ExtraData;
   3.555 +  alcMakeContextCurrent(NULL);
   3.556 +  ALuint i;
   3.557 +  // Destroy all slave contexts. LWJGL will take care of 
   3.558 +  // its own context.
   3.559 +  for (i = 1; i < data->numContexts; i++){
   3.560 +    context_data *ctxData = data->contexts[i];
   3.561 +    alcDestroyContext(ctxData->ctx);
   3.562 +    free(ctxData->renderBuffer);
   3.563 +    free(ctxData);
   3.564 +  }
   3.565 +  free(data);
   3.566 +  device->ExtraData = NULL;
   3.567 +}
   3.568 +
   3.569 +static ALCboolean send_reset_playback(ALCdevice *device)
   3.570 +{
   3.571 +  SetDefaultWFXChannelOrder(device);
   3.572 +  return ALC_TRUE;
   3.573 +}
   3.574 +
   3.575 +static void send_stop_playback(ALCdevice *Device){
   3.576 +  UNUSED(Device);
   3.577 +}
   3.578 +
   3.579 +static const BackendFuncs send_funcs = {
   3.580 +  send_open_playback,
   3.581 +  send_close_playback,
   3.582 +  send_reset_playback,
   3.583 +  send_stop_playback,
   3.584 +  NULL,
   3.585 +  NULL,  /* These would be filled with functions to    */
   3.586 +  NULL,  /* handle capturing audio if we we into that  */
   3.587 +  NULL,  /* sort of thing...                           */
   3.588 +  NULL,
   3.589 +  NULL
   3.590 +};
   3.591 +
   3.592 +ALCboolean alc_send_init(BackendFuncs *func_list){
   3.593 +  *func_list = send_funcs;
   3.594 +  return ALC_TRUE;
   3.595 +}
   3.596 +
   3.597 +void alc_send_deinit(void){}
   3.598 +
   3.599 +void alc_send_probe(enum DevProbe type)
   3.600 +{
   3.601 +  switch(type)
   3.602 +    {
   3.603 +    case DEVICE_PROBE:
   3.604 +      AppendDeviceList(sendDevice);
   3.605 +      break;
   3.606 +    case ALL_DEVICE_PROBE:
   3.607 +      AppendAllDeviceList(sendDevice);
   3.608 +      break;
   3.609 +    case CAPTURE_DEVICE_PROBE:
   3.610 +      break;
   3.611 +    }
   3.612 +}
   3.613 +#+end_src
   3.614 +
   3.615 +
   3.616 +
   3.617 +
   3.618 +
   3.619 +
   3.620 +
   3.621 +
   3.622 +#+srcname: ears
   3.623  #+begin_src clojure
   3.624 -(ns body.ear)
   3.625 +(ns cortex.hearing)
   3.626  (use 'cortex.world)
   3.627  (use 'cortex.import)
   3.628  (use 'clojure.contrib.def)
   3.629 @@ -41,21 +633,7 @@
   3.630  (import javax.swing.ImageIcon)
   3.631  (import javax.swing.JOptionPane)
   3.632  (import java.awt.image.ImageObserver)
   3.633 -#+end_src
   3.634  
   3.635 -JMonkeyEngine3's audio system works as follows:
   3.636 -first, an appropiate audio renderer is created during initialization
   3.637 -and depending on the context.  On my computer, this is the
   3.638 -LwjglAudioRenderer. 
   3.639 -
   3.640 -The LwjglAudioRenderer sets a few internal state variables depending
   3.641 -on what capabilities the audio system has.
   3.642 -
   3.643 -may very well need to make my own AudioRenderer
   3.644 -
   3.645 -#+srcname: ear-body-1
   3.646 -#+begin_src clojure :results silent
   3.647 -(in-ns 'body.ear)
   3.648  (import 'com.jme3.capture.SoundProcessor)
   3.649  
   3.650  
   3.651 @@ -72,7 +650,6 @@
   3.652  	 (.get audioSamples byte-array 0 numSamples)
   3.653  	 (continuation
   3.654  	  (vec byte-array)))))))
   3.655 -	 
   3.656  
   3.657  (defn add-ear 
   3.658    "add an ear to the world.  The continuation function will be called
   3.659 @@ -122,16 +699,19 @@
   3.660  
   3.661  
   3.662  
   3.663 +* Example
   3.664 +
   3.665  * COMMENT Code Generation
   3.666  
   3.667 -#+begin_src clojure :tangle /home/r/cortex/src/body/ear.clj
   3.668 -<<ear-header>>
   3.669 -<<ear-body-1>>
   3.670 +#+begin_src clojure :tangle ../../cortex/src/cortex/hearing.clj
   3.671 +<<ears>>
   3.672  #+end_src
   3.673  
   3.674 -
   3.675 -#+begin_src clojure :tangle /home/r/cortex/src/test/hearing.clj
   3.676 +#+begin_src clojure :tangle ../../cortex/src/test/hearing.clj
   3.677  <<test-hearing>>
   3.678  #+end_src
   3.679  
   3.680  
   3.681 +#+begin_src C :tangle ../Alc/backends/send.c
   3.682 +<<send>>
   3.683 +#+end_src