Mercurial > audio-send
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