Пример #1
0
/*
 * _alcSpeakerMove( ALuint cid )
 *
 * Moves speakers for context named by cid, using listener orientation and
 * position as modifiers.
 *
 * If cid is invalid, set ALC_INVALID_CONTEXT.
 *
 * assumes context cid is locked
 *
 * FIXME:
 *    please check my math
 */
void _alcSpeakerMove( ALuint cid ) {
    AL_context *cc;
    ALfloat vec[3];
    ALfloat *pos;    /* listener position */
    ALfloat *ori;    /* listener orientation */
    ALfloat ipos[3]; /* inverse listener position */
    ALuint i;
    ALfloat m[3][3];
    ALfloat pm[3];
    ALfloat rm[3];

    cc = _alcGetContext( cid );
    if(cc == NULL) {
        _alDebug(ALD_CONTEXT, __FILE__, __LINE__,
                 "_alcSpeakerMove: invalid context id %d", cid);

        _alcSetError( ALC_INVALID_CONTEXT );

        return;
    }

    pos = cc->listener.position;
    ori = cc->listener.orientation;

    _alVectorCrossProduct(vec, ori + 0, ori + 3);
    _alVectorNormalize(m[0], vec);

    _alVectorCrossProduct(vec, m[0], ori + 0);
    _alVectorNormalize(m[1], vec);

    _alVectorNormalize(m[2], ori + 0);

    /* reset speaker position */
    _alcSpeakerInit(cid);

    _alVectorInverse( ipos, cc->listener.position );

    /* rotate about at and up vectors */
    for(i = 0; i < _alcGetNumSpeakers(cid); i++) {
        _alVectorTranslate(pm,
                           cc->_speaker_pos[i].pos, ipos);

        _alVecMatrixMulA3(rm, pm, m);

        _alVectorTranslate(cc->_speaker_pos[i].pos,
                           rm, pos);
    }

    _alDebug(ALD_MATH, __FILE__, __LINE__,
             "SpAdj: l/r [%f|%f|%f] [%f|%f|%f]",
             cc->_speaker_pos[0].pos[0],
             cc->_speaker_pos[0].pos[1],
             cc->_speaker_pos[0].pos[2],

             cc->_speaker_pos[1].pos[0],
             cc->_speaker_pos[1].pos[1],
             cc->_speaker_pos[1].pos[2]);

    return;
}
Пример #2
0
/*
 * _alMixPoolDealloc( _alMixPool *mspool, int msindex,
 *                   void (*freer_func)(void *))
 *
 * Finalize a _alMixSource, indexed by msindex, using freer_func,
 * from mspool, marking is as not in use.
 */
ALboolean _alMixPoolDealloc( _alMixPool *spool, int msindex,
			     void (*freer_func)(void *) ) {
	_alMixSource *src;

	if( msindex < 0 ) {
		return AL_FALSE;
	}

	src = _alMixPoolIndex( spool, msindex );
	if(src == NULL) {
		_alDebug(ALD_MIXER, __FILE__, __LINE__,
			"%d is a bad index", msindex);

		return AL_FALSE;
	}

	if(spool->pool[msindex].inuse == AL_FALSE) {
		_alDebug(ALD_MIXER, __FILE__, __LINE__,
			"index %d is not in use", msindex);

		/* already deleted */
		return AL_FALSE;
	}

	spool->pool[msindex].inuse = AL_FALSE;

	freer_func(src);

	return AL_TRUE;
}
Пример #3
0
void *grab_write_sdl(void) {
        sdl_info.spec.freq     = DEF_SPEED;
        sdl_info.spec.channels = DEF_CHANNELS;
        sdl_info.spec.samples  = DEF_SAMPLES;
        sdl_info.spec.size     = DEF_SIZE;
        sdl_info.spec.format   = SDL_DEF_FMT;
        sdl_info.spec.callback = dummy;

        if(SDL_OpenAudio(&sdl_info.spec, NULL) < 0) {
		/* maybe we need SDL_Init? */
		SDL_Init(SDL_INIT_AUDIO);

		if(SDL_OpenAudio(&sdl_info.spec, NULL) < 0) {
			_alDebug(ALD_CONTEXT, __FILE__, __LINE__,
				"No SDL: %s", SDL_GetError());
			return NULL;
		}
        }

	if(ringbuffer != NULL) {
		free(ringbuffer);
	}

	ringbuffersize = 2 * sdl_info.spec.size;
	ringbuffer     = malloc(ringbuffersize);
	readOffset      = 0;
	writeOffset     = 0;

	_alBlitBuffer = firsttime_sdl_blitbuffer;

	_alDebug(ALD_CONTEXT, __FILE__, __LINE__,
		"SDL grab audio ok");

        return &sdl_info.spec;
}
Пример #4
0
ALboolean alutLoadWAV( const char *fname,
                        void **wave,
			ALsizei *format,
			ALsizei *size,
			ALsizei *bits,
			ALsizei *freq ) {
	ALushort alFmt  = 0;
	ALushort acChan = 0;
	ALushort acFreq = 0;
	ALuint   acSize = 0;

	if(ReadWAVFile(fname, wave,
			&alFmt, &acChan, &acFreq, &acSize) == AL_FALSE) {
		_alDebug(ALD_CONVERT, __FILE__, __LINE__,
			"ReadWAVFile failed for %s", fname);
		return AL_FALSE;
	}

	/* set output params */
	*format = (ALsizei) alFmt;
	*freq   = (ALsizei) acFreq;
	*size   = (ALsizei) acSize;
	*bits   = (ALsizei) _al_formatbits(alFmt);
	
	_alDebug(ALD_CONVERT, __FILE__, __LINE__,
		"alutLoadWAV %s with [alformat/size/bits/freq] = [0x%x/%d/%d]",
		fname,
		*format, *size, *freq);

	return AL_TRUE;
}
Пример #5
0
/* 0.0 - 2.0 in seconds */
void alReverbDelay_LOKI(ALuint sid, ALfloat param) {
	AL_source *src;

	if((param < 0.0) || (param > 2.0)) {
		/*
		 * For this kludge, the scale is 2 * normalized.
		 */
		_alDebug(ALD_MAXIMUS, __FILE__, __LINE__,
		      "alReverbDelay: invalid value %f",
		      param);

		_alDCSetError(AL_INVALID_VALUE);
		return;
	}

	_alcDCLockContext();

	src = _alDCGetSource(sid);
	if(src == NULL) {
		_alDebug(ALD_MAXIMUS, __FILE__, __LINE__,
		      "alReverbScale: invalid source id %d",
		      sid);

		_alDCSetError(AL_INVALID_NAME);
		return;
	}

	src->reverb_delay = param * canon_speed * _alGetChannelsFromFormat(canon_format);

	src->flags |= ALS_REVERB;

	_alcDCUnlockContext();

	return;
}
Пример #6
0
/*
 * index2ErrorNo( int index )
 *
 * Returns an al error from a simple index.
 */
static ALenum index2ErrorNo( int index ) {
	switch( index ) {
 		case 0:
			return AL_NO_ERROR;
			break;
		case 1:
			return AL_INVALID_NAME;
			break;
		case 2:
			return AL_ILLEGAL_ENUM;
			break;
		case 3:
			return AL_INVALID_VALUE;
			break;
		case 4:
			return AL_ILLEGAL_COMMAND;
			break;
		case 5:
			return AL_OUT_OF_MEMORY;
			break;
		default:
			_alDebug( ALD_ERROR, __FILE__, __LINE__,
				"Unknown index : %d", index );
			break;
	}

	return -1;
}
Пример #7
0
/*
 * ErrorNo2index( ALenum error_number )
 *
 * Returns a simple index from an al error.
 */
static int ErrorNo2index( ALenum error_number ) {
	switch( error_number ) {
		case AL_NO_ERROR:
			return 0;
			break;
		case AL_INVALID_NAME:
			return 1;
			break;
		case AL_ILLEGAL_ENUM:
			return 2;
			break;
		case AL_INVALID_VALUE:
			return 3;
			break;
		case AL_ILLEGAL_COMMAND:
			return 4;
			break;
		case AL_OUT_OF_MEMORY:
			return 5;
			break;
		default:
			_alDebug( ALD_ERROR, __FILE__, __LINE__,
				"Unknown error condition: 0x%x", error_number );
			return -1;
			break;
	}

	return -1;
}
Пример #8
0
/*
 * If sym has type ALRC_STRING, this call populates retstr ( up to len bytes )
 * with the value of the string.
 */
Rcvar rc_tostr0( Rcvar symp, char *retstr, size_t len ) {
	AL_rctree *sym = (AL_rctree *) symp;
	static AL_rctree retval;

	if(sym == NULL) {
		return NULL;
	}

	if(rc_type(sym) != ALRC_STRING) {
		_alDebug(ALD_CONFIG, __FILE__, __LINE__,
		      "Not a string");

		return NULL;
	}

	if(len > sym->data.str.len) {
		len = sym->data.str.len;
	}

	memcpy(retstr, sym->data.str.c_str, len);
	retstr[len] = '\0';

	retval = scmtrue;

	return &retval;
}
Пример #9
0
/*
 * Sets the attributes for the device from the settings in the device. The
 * library is free to change the parameters associated with the device, but
 * until _alcDeviceSet is called, none of the changes are important.
 *
 * Returns ALC_FALSE if the setting operation failed.  After a call to this
 * function, the caller should check the members in dev to see what the
 * actual values set are.
 */
ALCboolean _alcDeviceSet(AL_device *dev)
{
    _alDebug(ALD_CONTEXT, __FILE__, __LINE__,
             "requesting device buffer size %d, format 0x%x, speed %d",
             dev->bufferSizeInBytes, dev->format, dev->speed);

    if(!dev->ops->setAttributes(dev->privateData, &dev->bufferSizeInBytes,
                                &dev->format, &dev->speed)) {
        _alDebug(ALD_CONVERT, __FILE__, __LINE__, "alcDeviceSet_ failed");
        return ALC_FALSE;
    }

    _alDebug(ALD_CONTEXT, __FILE__, __LINE__,
             "got device buffer size %d, format 0x%x, speed %d",
             dev->bufferSizeInBytes, dev->format, dev->speed);
    return ALC_TRUE;
}
Пример #10
0
static ALboolean ReadWAVFile(const char *fname, void **pcmdata,
			ALushort *rfmt, ALushort *rchan, ALushort *rfreq,
			ALuint *rsize) {
	void *data;
	ALint len;  /* length of pcm portion */
	void *udata;

	if((rfmt == NULL) || (rchan == NULL) || (rfreq == NULL)) {
		/* bad mojo */
		return AL_FALSE;
	}

	len = _alSlurp(fname, &data);
	if(len < 0) {
		/* couldn't slurp audio file */
		_alDebug(ALD_CONVERT, __FILE__, __LINE__,
			"Could not slurp %s", fname);

		return AL_FALSE;
	}

	if(acLoadWAV(data, (ALuint *) &len, &udata,
		rfmt, rchan, rfreq) == NULL) {
		_alDebug(ALD_CONVERT, __FILE__, __LINE__,
			"Could not buffer and convert data");

		free(data);
		return AL_FALSE;
	}

	free(data);

	*rfmt    = _al_AC2ALFMT(*rfmt, *rchan);
	*rsize   = len;
	*pcmdata = udata;

	_alDebug(ALD_CONVERT, __FILE__, __LINE__,
		"ReadWAVFile [freq/size/acformat] = [%d/%d/0x%x]",
		*rfreq, *rsize, *rfmt);

	return AL_TRUE;
}
Пример #11
0
int _alLockPrintf( const char *msg, const char *fn, int ln ) {
	static char threadstr[2048];
	char blanks[] = "                             ";
	int maxlen = 18 - (strlen(fn) + log10(ln));

	blanks[maxlen] = '\0';

	sprintf(threadstr, "%s[%u]", blanks, tlSelfThread());

	return _alDebug(ALD_LOCK, fn, ln, "%s %s", threadstr, msg);
}
Пример #12
0
/*
 * rc_foreach( Rcvar ls, Rcvar (*op)( Rcvar operand ))
 *
 * For each member in ls, apply op to the member.
 */
void rc_foreach( Rcvar ls, Rcvar (*op)(Rcvar operand) ) {
	if( rc_type( ls ) != ALRC_CONSCELL ) {
		_alDebug( ALD_CONFIG, __FILE__, __LINE__, "rc_foreach failed");
		return;
	}

	op( rc_car(ls) );

	rc_foreach( rc_cdr( ls ), op );

	return;
}
Пример #13
0
void *grab_write_esd(void) {
	esd_format_t fmt;
	int socket;
	const char *esdkey = genesdkey();
	const char *espeaker = getenv("ESPEAKER");
	int esd;

	esd = esd_open_sound(espeaker);
	if(esd < 0) {
		fprintf(stderr, "esd open sound failed.\n");
		return NULL;
	}

	fmt = ESD_STREAM | ESD_PLAY;

	switch(DEF_CHANNELS) {
		case 1: fmt |= ESD_MONO; break;
		case 2: fmt |= ESD_STEREO; break;
		default: break;
	}

	switch(_al_formatbits(DEF_FORMAT)) {
		case 8:  fmt |= ESD_BITS8; break;
		case 16: fmt |= ESD_BITS16; break;
		default: break;
	}

	socket = esd_play_stream(fmt, DEF_SPEED, espeaker, esdkey);

	if(socket < 0) {
		fprintf(stderr, "esd play stream failed.\n");
		return NULL;
	}

	_alBlitBuffer = esd_blitbuffer;

	fprintf(stderr, "esd grab audio ok\n");

	_alDebug(ALD_CONTEXT, __FILE__, __LINE__,
		"esd grab audio ok");

	esd_info.speed     = DEF_SPEED;
	esd_info.fmt       = fmt;
	esd_info.socket    = socket;
	esd_info.espeaker  = espeaker;
	esd_info.paused    = AL_FALSE;
	esd_info.esdhandle = esd;

	strncpy(esd_info.name, esdkey, ESD_NAMELEN);

        return &esd_info;
}
Пример #14
0
/*
 * _alExit( void )
 *
 * Finalizes things when the last device is deleted.
 *
 * FIXME: we can probably clean a lot of this up now that we have
 * alc{Open,Close}Device.
 */
void _alExit( void ) {
	int i;

	_alDebug( ALD_MAXIMUS, __FILE__, __LINE__, "_alExit called" );

#ifndef NO_THREADING
	/* we could be sync, so we check mixthread for a valid ID */
	if(mixthread != NULL) {
		time_for_mixer_to_die = AL_TRUE;

		_alWaitThread( mixthread );

		while( time_for_mixer_to_die == AL_TRUE ) {
			_alMicroSleep(100000);
		}
	}
#endif /* NO_THREADING */

	for(i = 0; i < _ALC_MAX_CHANNELS; i++) {
		if(f_buffers.data[i] != NULL) {
			free( f_buffers.data[i] );
			f_buffers.data[i] = NULL;
		}
	}

	f_buffers.len = 0;

	_alDestroyConfig();

	_alDestroyExtensions();
	_alDestroyExtensionGroups( );
	_alDestroyMixer();
	_alDestroyFilters();

	_alcDestroyAll();

	_alDestroyBuffers(); /* buffers after mixer and alc destroy */

	/* do builtin extensions destruction */
	BUILTIN_EXT_LOKI_FINI;
	BUILTIN_EXT_MP3_FINI;
	BUILTIN_EXT_VORBIS_FINI;

	alDLExit_ ();
}
Пример #15
0
/*
 * alGenStreamingBuffers_LOKI
 *
 * Perform full allocation in buffers[0..n-1].  If full allocation
 * is not possible, the appropriate error is set and the function
 * returns.  Each buffer id in a sucessful call can be used with
 * BufferAppendData.
 *
 * If n is 0, legal nop.  If n < 0, set INVALID_VALUE and nop.
 *
 */
void alGenStreamingBuffers_LOKI( ALsizei n, ALuint *buffer) {
	AL_buffer *buf;
	int i;

	if(n == 0) {
		/* silently return */
		return;
	}

	if(n < 0) {
		_alDebug(ALD_BUFFER, __FILE__, __LINE__,
		      "alGenStreamingBuffers_LOKI: invalid n %d\n", n);

		_alcDCLockContext();
		_alDCSetError( AL_INVALID_VALUE );
		_alcDCUnlockContext();

		return;
	}

	/* generate normal buffers */
	alGenBuffers( n, buffer );

	_alLockBuffer();

	for( i = 0; i < n; i++ ) {
		buf = _alGetBuffer( buffer[i] );
		if( buf == NULL ) {
			/* allocation must have failed */
			_alUnlockBuffer();

			return;
		}

		/* make sure to set the streaming flag */
		buf->flags |= ALB_STREAMING;
	}

	_alUnlockBuffer();

	return;
}
Пример #16
0
void alBufferi_LOKI(ALuint buffer, ALenum param, ALint value) {
	AL_buffer *buf = NULL;

	_alLockBuffer();
	buf = _alGetBuffer(buffer);

	if(buf == NULL) {
		_alUnlockBuffer();

		_alDebug(ALD_BUFFER, __FILE__, __LINE__,
			"buffer id %d is a bad index", buffer);

		_alDCSetError(AL_INVALID_NAME);
		return;
	}

	switch(param) {
		case AL_FREQUENCY:
		  buf->frequency = value;
		  break;
		case AL_BITS:
		  switch(value) {
		      case 8:
			switch(_alGetChannelsFromFormat(buf->format)) {
			    case 1:
			      buf->format = AL_FORMAT_MONO8;
			      break;
			    case 2:
			      buf->format = AL_FORMAT_STEREO8;
			      break;
			    default:
			      break;
			}
			break;
		      case 16:
			switch(_alGetChannelsFromFormat(buf->format)) {
			    case 1:
			      buf->format = AL_FORMAT_MONO16;
			      break;
			    case 2:
			      buf->format = AL_FORMAT_STEREO16;
			      break;
			    default:
			      break;
			}
			break;
		  }
		  break;
		case AL_CHANNELS:
		  switch(value) {
		      case 1:
			switch(_alGetBitsFromFormat(buf->format)) {
			    case 8:
			      buf->format = AL_FORMAT_MONO8;
			      break;
			    case 16:
			      buf->format = AL_FORMAT_MONO16;
			      break;
			    default: break;
			}
			break;
		      case 2:
			switch(_alGetBitsFromFormat(buf->format)) {
			    case 8:
			      buf->format = AL_FORMAT_STEREO8;
			      break;
			    case 16:
			      buf->format = AL_FORMAT_STEREO16;
			      break;
			}
			break;
		  }
		  break;
		case AL_SIZE:
		  buf->size = value;
		  break;
		default:
		  _alDebug(ALD_BUFFER, __FILE__, __LINE__,
			"alBufferi bad param 0x%x", param);

		  _alDCSetError(AL_INVALID_ENUM);
		  break;
	}

	_alUnlockBuffer();

	return;
}
Пример #17
0
/*
 * _alInit( void )
 *
 * _alInit is called when the "first" device is created.  If all
 * devices are deleted, and then one is created, it is called again.
 *
 * Returns AL_TRUE unless some weird sort of memory allocation problem occurs,
 * in which case AL_FALSE is returned.
 */
ALboolean _alInit( void ) {
	ALboolean err;
	ALuint i;

	_alDebug( ALD_MAXIMUS, __FILE__, __LINE__, "_alInit called" );
	
	alDLInit_ ();
	
	_alDetectCPUCaps();

	/* set up SIMD FloatMul */
#ifdef HAVE_SSE2
	if (_alHaveSSE2())
		_alFloatMul = _alFloatMul_SSE2;
	else
#endif /* HAVE_SSE2 */
#ifdef HAVE_MMX
	if (_alHaveMMX())
		_alFloatMul = _alFloatMul_MMX;
	else
#endif /* HAVE_MMX */
	_alFloatMul = _alFloatMul_portable;

	for(i = 0; i < _ALC_MAX_CHANNELS; i++) {
		f_buffers.data[i]   = NULL;
	}

	f_buffers.len = 0;

	/* buffer initializations */
	err = _alInitBuffers();
	if(err == AL_FALSE) {
		return AL_FALSE;
	}

	if( _alInitMixer() == AL_FALSE ) {
		return AL_FALSE;
	}

	/* extension initilizations */
	err = _alInitExtensions();
	if(err == AL_FALSE) {
		_alDestroyBuffers();

		return AL_FALSE;
	}

#ifdef BUILTIN_EXT_LOKI
	/* FIXME: dynamic-ify this */
	/* register extension groups */
	_alRegisterExtensionGroup( (const ALubyte*) "ALC_LOKI_audio_channel" );
	_alRegisterExtensionGroup( (const ALubyte*) "AL_LOKI_buffer_data_callback" );
	_alRegisterExtensionGroup( (const ALubyte*) "AL_LOKI_IMA_ADPCM_format" );
	_alRegisterExtensionGroup( (const ALubyte*) "AL_LOKI_WAVE_format" );
	_alRegisterExtensionGroup( (const ALubyte*) "AL_LOKI_play_position" );
	_alRegisterExtensionGroup( (const ALubyte*) "AL_LOKI_quadriphonic" );

#ifdef ENABLE_EXTENSION_AL_EXT_MP3
	 _alRegisterExtensionGroup( (const ALubyte*) "AL_EXT_MP3" );
#endif /* ENABLE_EXTENSION_AL_EXT_MP3 */

#ifdef ENABLE_EXTENSION_AL_EXT_VORBIS
	_alRegisterExtensionGroup( (const ALubyte*) "AL_EXT_vorbis" );
#endif /* ENABLE_EXTENSION_AL_EXT_VORBIS */

#endif /* BUILTIN_EXT_LOKI */

	_alRegisterExtensionGroup( (const ALubyte*) "AL_EXT_capture" );
	_alRegisterExtensionGroup( (const ALubyte*) "ALC_EXT_capture" );
	_alRegisterExtensionGroup( (const ALubyte*) "AL_EXT_offset" );

	for(i = 0; exts[i].addr != NULL; i++) {
		_alRegisterExtension(exts[i].name, exts[i].addr);
	}

	/* do builtin extensions initialization */
	BUILTIN_EXT_LOKI_INIT;
	BUILTIN_EXT_MP3_INIT;
	BUILTIN_EXT_VORBIS_INIT;

	return AL_TRUE;
}
Пример #18
0
/*
 * alQueuei( ALuint sid, ALenum param, ALint i1 )
 *
 * Obsolete function.  Remove this.
 */
void alQueuei( ALuint sid, ALenum param, ALint i1 ) {
	AL_source *src;
	ALboolean inrange = AL_FALSE;

	SOURCELOCK();
	src = _alDCGetSource(sid);
	if(src == NULL) {
		_alDCSetError(AL_INVALID_NAME);
		SOURCEUNLOCK();

		return;
	}

	/*
	 * all calls to alQueuei specify either ALboolean parameters,
	 * which means that i1 is either AL_TRUE, AL_FALSE, or
	 * a buffer id.  So check for validity of i1 first, and
	 * set error if that's the case.
	 */
	switch(param) {
		case AL_LOOPING:
		case AL_SOURCE_RELATIVE:
		  inrange = _alCheckRangeb(i1);
		  break;
		case AL_BUFFER:
		  inrange = alIsBuffer(i1);
		  break;
		default:
		  /* invalid param,  error below. */
		  break;
	}

	if(inrange == AL_FALSE) {
		_alDebug(ALD_SOURCE, __FILE__, __LINE__,
		      "alQueuei(%d, 0x%x, ...) called with invalid value %d",
		      sid, param, i1);

		_alDCSetError(AL_INVALID_VALUE);
		
		SOURCEUNLOCK();
		return;
	}

	switch(param) {
		/* FIXME: add loop count */
		case AL_BUFFER:
		  /* Append bid to end */
		  _alSourceQueueAppend(src, i1);
		  break;
		default:
		  _alDebug(ALD_SOURCE, __FILE__, __LINE__,
			"alQueuei: invalid or stubbed source param 0x%x",
			param);
			
		  _alDCSetError(AL_ILLEGAL_ENUM);
		  break;
	}

	SOURCEUNLOCK();

	return;
}
Пример #19
0
/*
 * _alSourceUnqueueBuffers( ALuint sid, ALsizei n, ALuint *bids )
 *
 * Non locking version of alSourceUnqueueBuffers.
 *
 * assumes locked context
 */
void _alSourceUnqueueBuffers(ALuint sid, ALsizei n, ALuint *bids ) {
	AL_source *src;
	ALuint *tempqueue;
	AL_sourcestate *tempstate;
	struct dualarray *dualbuffers; /* the source's bid queue */
	struct dualarray *dualbids;   /* the passer's bids */
	int newsize;
	int i;
	int j;

	if(n == 0) {
		/* legal nop */
		return;
	}

	if(n < 0) {
		/* bad n */
		_alDCSetError( AL_INVALID_VALUE );

		_alDebug(ALD_SOURCE, __FILE__, __LINE__,
			"alSourceUnqueueBuffers: invalid numBuffers %d", n );

		return;
	}

	src = _alDCGetSource( sid );
	if(src == NULL) {
		_alDCSetError(AL_INVALID_NAME);
		return;
	}

	if(n >= src->bid_queue.read_index) {
		/* User has requested too many buffers unqueued */
		_alDCSetError( AL_INVALID_VALUE );

		_alDebug(ALD_SOURCE, __FILE__, __LINE__,
			"alSourceUnqueueBuffers: invalid numBuffers %d", n );

		return;
	}

	dualbuffers = malloc( src->bid_queue.size * sizeof *dualbuffers );
	if( dualbuffers == NULL ) {
		_alDCSetError( AL_OUT_OF_MEMORY );

		return;
	}

	dualbids =  malloc( n * sizeof *dualbuffers );
	if( dualbids == NULL ) {
		free( dualbuffers );
		_alDCSetError( AL_OUT_OF_MEMORY );

		return;
	}

	/* mark */
	for( i = 0; i < src->bid_queue.size; i++ ) {
		dualbuffers[i].id = src->bid_queue.queue[i];
		dualbuffers[i].index = i;
	}

	for( i = 0; i < n; i++ ) {
		dualbids[i].id = bids[i];
		dualbids[i].index = i;
	}

	/*
	 * sort both the source's bids and the passer's deletion
	 * request.
	 */
	qsort( dualbuffers, src->bid_queue.size,
		sizeof *dualbuffers, dualarray_id_cmp );
	qsort( dualbids, n, sizeof *dualbids, dualarray_id_cmp );

	/* sweep */
	newsize = src->bid_queue.size;
	for( i = 0, j = 0; i < n; i++ ) {
		if( dualbids[j].id == dualbuffers[i].id ) {
			dualbuffers[i].id    = 0;
			dualbuffers[i].index = -1;

			_alBidRemoveQueueRef( dualbids[j].id, src->sid );

			j++;
			newsize--;
		}
	}
			
	tempqueue = malloc(newsize * sizeof *tempqueue);
	if(tempqueue == NULL) {
		/*
		 * ouch
		 */
		_alDCSetError( AL_INVALID_VALUE );

		free( dualbids );
		free( dualbuffers );

		return;

	}

	tempstate = malloc(newsize * sizeof *tempstate);
	if(tempstate == NULL) {
		/* too late
		 *
		 * FIXME: re-add queuerefs removed above */
		_alDCSetError(AL_INVALID_VALUE);

		free( tempqueue );
		free( dualbids );
		free( dualbuffers );

		return;

	}

	/* unsort */
	qsort( dualbuffers, src->bid_queue.size,
		sizeof *dualbuffers, dualarray_index_cmp );

	/* rewrite */

	/* first, skip the 0'd out stuff */
	for( i = 0; dualbuffers[i].id == 0; i++ ) {
		/*
		 * ouch.  not sure about read_index or write_index
		 * moving.
		 */
		if(src->bid_queue.read_index >= i) {
			src->bid_queue.read_index--;
		}

		if(src->bid_queue.write_index >= i) {
			src->bid_queue.write_index--;
		}
	}

	for(j = 0; j < newsize; j++, i++) {
		tempqueue[j] = src->bid_queue.queue[i];
		tempstate[j] = src->bid_queue.queuestate[i];
	}

	/* free and assign */
	free( dualbuffers );
	free( dualbids );

	free( src->bid_queue.queue );
	free( src->bid_queue.queuestate );

	src->bid_queue.queue      = tempqueue;
	src->bid_queue.queuestate = tempstate;
	src->bid_queue.size       = newsize;

	return;
}
Пример #20
0
/*
 * alSourceQueueBuffers( ALuint sid, ALsizei numBuffers, ALuint *bids )
 *
 * Queue bids[0..numBuffers-1] to the source named sid, setting
 * AL_INVALID_VALUE if numBuffers < 0, or AL_INVALID_NAME if either sid or and
 * bid in bids[0..numBuffers-1] is not a valid buffer.
 */
void alSourceQueueBuffers( ALuint sid, ALsizei numBuffers, ALuint *bids ) {
	AL_source *src;
	ALsizei i;

	if( numBuffers == 0) {
		/* with n == 0, we NOP */
		return;
	}

	if( numBuffers < 0) {
		_alDebug(ALD_SOURCE, __FILE__, __LINE__,
		      "alSourceQueueBuffers: illegal n value %d\n", numBuffers );

		_alcDCLockContext();
		_alDCSetError( AL_INVALID_VALUE );
		_alcDCUnlockContext();

		return;
	}

	SOURCELOCK();

	src = _alDCGetSource( sid );
	if( src == NULL ) {
		_alDCSetError( AL_INVALID_NAME );

		_alDebug(ALD_SOURCE, __FILE__, __LINE__,
		      "alSourceQueueBuffers: invalid sid %d\n", sid );

		SOURCEUNLOCK();

		return;
	}

	_alLockBuffer();

	/* make sure that bids are valid */
	for( i = 0; i < numBuffers; i++ ) {
		if( _alIsBuffer( bids[i] ) == AL_FALSE ) {
			/*
			 * we have an invalid bid.  bid 0 is okay but the
			 * rest are not.
			 */
			if( bids[i] != 0 ) {
				_alUnlockBuffer();

				_alDCSetError( AL_INVALID_NAME );

				SOURCEUNLOCK();

				return;
			}
		}
	}

	/* now, append the bids */
	for( i = 0; i < numBuffers; i++ ) {
		if( bids[i] != 0 ) {
			/*
			 * only append non-0 bids, because we don't
			 * need them anyway.
			 */
		  	_alSourceQueueAppend( src, bids[i] );
		}
	}

	/* we're done */

	_alUnlockBuffer();
	SOURCEUNLOCK();

	return;
}
Пример #21
0
/*
 * Opens a device, using the alrc expression deviceSpecifier to specify
 * attributes for the device.  Returns the device if successful, NULL
 * otherwise.
 */
ALCdevice *alcOpenDevice( const ALchar *deviceSpecifier ) {
	ALCdevice *retval;
	char dirstr[65];
	Rcvar direction = NULL;
	Rcvar freq_sym = NULL;
	Rcvar speakers = NULL;
	Rcvar devices = NULL;
	int openForInput;

	if( num_devices == 0 ) {
		/* first initialization */
		if( _alParseConfig() == AL_FALSE ) {
			_alDebug(ALD_CONFIG, __FILE__, __LINE__,
				"Couldn't parse config file.");
		}
		if( _alInit() == AL_FALSE ) {
			_alDebug(ALD_CONFIG, __FILE__, __LINE__,
				"Couldn't initialize OpenAL.");
		}
	}

    /* If the name starts with a ', then it's a device configuration */
    if(deviceSpecifier && deviceSpecifier[0] == '\'') {
        Rcvar listOfLists;

        /* see if the user defined devices, sampling-rate, or direction */
        devices   = rc_lookup( "devices" );
        direction = rc_lookup( "direction" );
        freq_sym  = rc_lookup( "sampling-rate" );
        speakers  = rc_lookup( "speaker-num" );

        listOfLists = rc_eval( deviceSpecifier );
        rc_foreach( listOfLists, rc_define_list );
        /* Got a config, so remove the name from further processing */
        deviceSpecifier = NULL;

        /* redefine the stuff we saved */
        if( direction != NULL )
            rc_define( "direction", alrc_quote( direction ));

        if( devices != NULL )
            rc_define( "devices", alrc_quote( devices ) );

        if( freq_sym != NULL )
            rc_define( "sampling-rate", alrc_quote( freq_sym ));

        if( speakers != NULL )
            rc_define( "speaker-num", alrc_quote( speakers ));
    }


	direction = rc_lookup( "direction" );
	devices   = rc_lookup( "devices" );
	freq_sym  = rc_lookup( "sampling-rate" );
	speakers  = rc_lookup( "speaker-num" );

	memset( dirstr, 0, sizeof(dirstr) );
	
	if( direction != NULL ) {
		switch( rc_type( direction ) ) {
			case ALRC_STRING:
				rc_tostr0(direction, dirstr, 64);
				break;
			case ALRC_SYMBOL:
				rc_symtostr0(direction, dirstr, 64);
				break;
			default:
				break;
		}
	}

	retval = malloc( sizeof *retval );
	if( retval == NULL) {
		/* FIXME: set AL_OUT_OF_MEMORY here? */

		return NULL;
	}

	/* defaults */
	retval->format = _ALC_EXTERNAL_FMT;
	retval->speed  = _ALC_EXTERNAL_SPEED;
	retval->flags  = ALCD_NONE;

	if( freq_sym != NULL ) {
		switch(rc_type( freq_sym )) {
			case ALRC_INTEGER:
			case ALRC_FLOAT:
				retval->speed = rc_toint( freq_sym );
				break;
			default:
				_alDebug(ALD_CONVERT, __FILE__, __LINE__,
					"invalid type for sampling-rate");
				break;
		}
	}

	if( speakers != NULL ) {
		switch(rc_type( speakers )) {
			case ALRC_INTEGER:
			case ALRC_FLOAT:
				{
					ALint s = rc_toint( speakers );
					if (s >= 0) {
						ALenum fmt = _al_formatscale( retval->format, (ALuint)s );
						if ( fmt >= 0 ) {
							retval->format = fmt;
						}
					}
				}
				break;
			default:
				break;
		}
	}

	openForInput = (strncmp( dirstr, "read", 64 ) == 0);
	alcBackendOpen_(deviceSpecifier, (openForInput ? ALC_OPEN_INPUT_ : ALC_OPEN_OUTPUT_), &retval->ops, &retval->privateData );
	if( retval->privateData == NULL ) {
		free( retval );
		return NULL;
	}
        /* set specifier */
        retval->specifier = retval->ops->getName(retval->privateData);
	retval->flags |= ( openForInput ? ALCD_READ : ALCD_WRITE );

	num_devices++;

	/* Figure out the size of buffer to request from the device based
	 * on the bytes per sample and speed */
	retval->bufferSizeInBytes  = _alSmallestPowerOfTwo(retval->speed / 15);
	retval->bufferSizeInBytes *= _alGetChannelsFromFormat(retval->format);
	retval->bufferSizeInBytes *= _alGetBitsFromFormat(retval->format) / 8;
	if(_alcDeviceSet(retval) == ALC_FALSE) {
		alcCloseDevice(retval);
		return NULL;
	}

	return retval;
}
Пример #22
0
/**
 *
 * alBufferWriteData_LOKI( ALuint  bid,
 *               ALenum  format,
 *               ALvoid  *data,
 *               ALsizei size,
 *               ALsizei freq
 *               ALenum  internalFormat )
 *
 * associates data with bid, with format hint
 *
 * If format is invalid, set AL_INVALID_ENUM.  If bid is not a valid buffer
 * name, set AL_INVALID_NAME.  If not enough memory is available to make a
 * copy of this data, set AL_OUT_OF_MEMORY.
 */
void alBufferWriteData_LOKI( ALuint  bid,
		   ALenum  format,
                   void   *data,
		   ALsizei size,
		   ALsizei freq,
		   ALenum internalFormat ) {
	AL_buffer *buf;
	unsigned int retsize;
	void *cdata;
	ALuint i;

	_alLockBuffer();

	buf = _alGetBuffer(bid);
	if(buf == NULL) {
		_alDebug(ALD_BUFFER, __FILE__, __LINE__,
		      "alBufferData: buffer id %d not valid",
		      bid);

		_alDCSetError(AL_INVALID_NAME);

		_alUnlockBuffer();
		return;
	}

	cdata = _alBufferCanonizeData(format,
				      data,
				      size,
				      freq,
				      internalFormat,
				      buf->frequency,
				      &retsize,
				      AL_FALSE);

	if(cdata == NULL) {
		/*  _alBufferCanonize Data should set error */
		_alUnlockBuffer();
		return;
	}

	if(buf->flags & ALB_STREAMING) {
		/* Streaming buffers cannot use alBufferData */
		_alDCSetError(AL_INVALID_OPERATION);

		free(cdata);

		_alUnlockBuffer();

		return;
	}

	buf->format = internalFormat;

	if(buf->size < retsize)
	{
		void *temp_copies[_ALC_MAX_CHANNELS] = { NULL };
		ALboolean success = AL_TRUE;

		/* don't use realloc */
		_alBufferFreeOrigBuffers(buf);

		for(i = 0; i < _alGetChannelsFromFormat(buf->format); i++)
		{
			temp_copies[i] = malloc(retsize);
			success = (temp_copies[i] != NULL) ? AL_TRUE : AL_FALSE;
		}

		if(!success)
		{
			free(cdata);

			for(i = 0; i < _alGetChannelsFromFormat(buf->format); i++)
			{
				free(temp_copies[i]);
			}

			/* JIV FIXME: lock context */
			_alcDCLockContext();
			_alDCSetError(AL_OUT_OF_MEMORY);
			_alcDCUnlockContext();

			_alUnlockBuffer();

			return;
		}

		switch(_alGetChannelsFromFormat(buf->format))
		{
			case 1:
			  for(i = 0; i < elementsof(buf->orig_buffers); i++)
			  {
				  buf->orig_buffers[i] = temp_copies[0];
			  }

			  break;
			case 2:
			  for(i = 0; i < elementsof(buf->orig_buffers); i += 2)
			  {
				  buf->orig_buffers[i]   = temp_copies[0];
				  buf->orig_buffers[i+1] = temp_copies[1];
			  }

			  break;
			case 4:
			  assert(elementsof(buf->orig_buffers) >= 4);
			  for(i = 0; i < elementsof(buf->orig_buffers); i += 4)
			  {
				  buf->orig_buffers[i]   = temp_copies[0];
				  buf->orig_buffers[i+1] = temp_copies[1];
				  buf->orig_buffers[i+2] = temp_copies[2];
				  buf->orig_buffers[i+3] = temp_copies[3];
			  }
			  break;
			case 6:
			  assert(elementsof(buf->orig_buffers) >= 6);
			  for(i = 0; i < elementsof(buf->orig_buffers); i += 6)
			  {
				  buf->orig_buffers[i]   = temp_copies[0];
				  buf->orig_buffers[i+1] = temp_copies[1];
				  buf->orig_buffers[i+2] = temp_copies[2];
				  buf->orig_buffers[i+3] = temp_copies[3];
				  buf->orig_buffers[i+4] = temp_copies[4];
				  buf->orig_buffers[i+5] = temp_copies[5];
			  }

			  break;
			default:
			  /* well this is weird */
			  assert(0);
			  break;
		}
	}


	_alMonoify((ALshort **) buf->orig_buffers,
		   cdata,
		   retsize / _alGetChannelsFromFormat(buf->format),
		   buf->num_buffers, _alGetChannelsFromFormat(buf->format));

	free(cdata);

	buf->size = retsize / _alGetChannelsFromFormat(buf->format);

	_alUnlockBuffer();

	return;
}
Пример #23
0
/**
 * Specify data to be filled into a looping buffer.
 * This takes the current position at the time of the
 *  call, and returns the number of samples written.
 *
 *  FIXME: this version is not as stingy about memory as
 *         it could be.
 *
 *  FIXME: move convert to the bottom of the testing, so
 *   	   that only as much data as is being used will be
 *   	   converted.
 *
 *  FIXME: mostly untested
 *
 *  FIXME: this is the most horrible function ever.  I can only
 *  	   claim responsibility for 50% of the hideous horror that
 *  	   is this function.  Before you smite me to eternal damnation
 *  	   for the monstrosity that follows, please keep in mind that
 *  	   the remaining half of the horror belongs squarely on those
 *  	   who defined the semantics and side effects of this disgusting
 *  	   monster.
 *
 */
ALsizei alBufferAppendData_LOKI( ALuint   buffer,
                            ALenum   format,
                            void*    data,
		            ALsizei  osamps,
                            ALsizei  freq ) {
	AL_buffer *buf;
	ALuint osize;  /* old size */
	ALuint csize;  /* converted size */
	ALuint nsamps; /* number of samples that csize represents */
	ALuint csamps; /* number of samples to convert */
	ALuint psize;  /* predicted size of passed data after conversion */
	ALuint orig_csamps; /* original number of samples to convert, pre truncation */
	unsigned int remainingspace = 0;
	unsigned int copyoffset = 0;
	unsigned int copysize   = 0;
	ALenum tformat = 0; /* buffer's target format */
	ALuint tfreq = 0;   /* buffer's target frequency */
	void *temp = NULL;
	ALuint i;

	_alLockBuffer();

	buf = _alGetBuffer(buffer);
	if(buf == NULL) {
		/* invalid buffers go */
		_alUnlockBuffer();

		_alDebug(ALD_BUFFER, __FILE__, __LINE__,
			"buffer id %d is invalid",
			buffer);

		_alDCSetError(AL_INVALID_NAME);

		return 0;
	}

	/*
	 * Non streaming buffers go bye bye
	 */
	if(!(buf->flags & ALB_STREAMING)) {
		_alUnlockBuffer();

		_alDebug(ALD_STREAMING, __FILE__, __LINE__,
			"buffer id %d not created with alGenStreamingBuffer",
			buffer);

		_alDCSetError(AL_INVALID_OPERATION);

		return 0;
	}

	/* initialize stuff */

	osize = buf->size;

	/*
	 * Set csamps to the size of osamps in bytes.
	 *
	 * make sure that csamps contains an even multiple of
	 * the number of channels
	 */
	csamps  = osamps;
	csamps -= (csamps % _alGetChannelsFromFormat(format));
	csamps *= (_alGetBitsFromFormat(format) / 8);

	orig_csamps = csamps;

	/* Set psize to the value that csamps would be in converted format */
	psize = _al_PCMRatioify(freq, buf->frequency, format, buf->format, csamps);

	/* set nsamps */
	nsamps = osamps;

	if(buf->streampos > buf->size) {
		/* underflow! */
		_alDebug(ALD_STREAMING,
			__FILE__, __LINE__, "underflow! sp|size %d|%d",
			buf->streampos, buf->size);

		buf->streampos = buf->appendpos = 0;
		remainingspace = buf->size;
	} else if(buf->appendpos > buf->streampos) {
		remainingspace = buf->size - buf->appendpos;
	} else if(buf->size != 0) {
		remainingspace = buf->streampos - buf->appendpos;
	} else {
		remainingspace = 0;
	}

	if((remainingspace >= MINSTREAMCHUNKSIZE) ||
	   (psize <= remainingspace)) {
		/* only take enough space to fill buffer. */
		_alDebug(ALD_STREAMING, __FILE__, __LINE__,
		"fill data to end: rs|sp|ap. %d|%d|%d",
			remainingspace, buf->streampos, buf->appendpos);

		if(remainingspace < psize) {
			copysize = remainingspace;
		} else {
			copysize = psize;
		}

		/* scale samples */
		nsamps *= copysize;
		nsamps /= psize;

		/* remember to set copyoffset for offset_memcpy below */
		copyoffset = buf->appendpos;

		buf->appendpos += copysize;
	} else if((osize > EXPANDSTREAMBUFSIZE)         &&
		  (buf->streampos > MINSTREAMCHUNKSIZE) &&
	          (buf->appendpos > buf->streampos)) {
		/*
		 *  Okay:
		 *
		 *  Since streampos is after append pos, and
		 *  streampos is less than the min stream chunk
		 *  size, we can safely wrap around and put the
		 *  data at the beginning (the WRAP flag gets
		 *  removed elsewhere.
		 *
		 *  The only thing is, if the buffer is still
		 *  fairly small, it would be nice to expand it
		 *  so that it can accomodate more data (within
		 *  reason).  So we check to see if the size
		 *  greater than a certain threshold (expandbuffersize),
		 *  below which we defer to allow BufferAppendData to
		 *  expand the buffer.
		 */
		_alDebug(ALD_STREAMING, __FILE__, __LINE__,
			"reset offset 0 osize|psize|sp|ap|rs %d|%d|%d|%d|%d",
			osize, psize, buf->streampos, buf->appendpos,
			remainingspace);

		if(buf->streampos < psize) {
			copysize = buf->streampos;
		} else {
			copysize = psize;
		}

		/* scale samples */
		nsamps *= copysize;
		nsamps /= psize;

		copyoffset = 0;

		buf->appendpos = copysize;

		/* we can wrap. */
		buf->flags |= ALB_STREAMING_WRAP;
	} else if(buf->streampos < buf->appendpos) {
		unsigned int newsize;

		_alDebug(ALD_STREAMING, __FILE__, __LINE__,
			"eb time: size|rs|ap|sp      %d|%d|%d|%d",
			osize, remainingspace, buf->appendpos, buf->streampos);

		/* we must expand the size of our buffer */
		newsize = buf->appendpos + psize;

		assert(newsize >= osize);

		for(i = 0; i < buf->num_buffers; i++) {
			temp = realloc(buf->orig_buffers[i], newsize);
			if(temp == NULL) {
				_alUnlockBuffer();

				return 0;
			}

			buf->orig_buffers[i] = temp;
		}

		/* set copy params for offset_memcpy below */
		copyoffset = buf->appendpos;
		copysize   = psize;

		/* reset size */
		buf->size = newsize;

		/*
		 * set append
		 */
		buf->appendpos += psize;
	}  else if(buf->size > 0) {
		/* not ready to accept data */
		_alDebug(ALD_STREAMING, __FILE__, __LINE__,
			"osize|sp|ap|rs %d|%d|%d|%d",
			osize,
			buf->streampos,
			buf->appendpos,
			remainingspace);

		_alUnlockBuffer();
		return 0;
	}

	/*
	 * unlock buffer for time intensive stuff, but
	 * get buffer params first
	 */
	tformat = buf->format;
	tfreq   = buf->frequency;

	_alUnlockBuffer();

	/*
	 *  Recompute csamps to reflect a decrease of the amount of
	 *  data that we will use.
	 */
	csamps  = nsamps;
	csamps -= (csamps % _alGetChannelsFromFormat(format));
	csamps *= (_alGetBitsFromFormat(format) / 8);

	/*
	 * We should decide how much data to use such that csize is
	 * a reasonable number.
	 *
	 * bufferAppendScratch = converted data scratch space
	 * csize = converted data's size
	 *
	 * nsamps = number of samples that csize represents
	 */
	if(scratch.size < csamps * (_alGetBitsFromFormat(format)/8)) {
		temp = realloc(scratch.data, csamps * (_alGetBitsFromFormat(format)/8));
		if(temp == NULL) {
			/* oops */
			return 0;
		}

		scratch.data = temp;
		scratch.size = csamps * (_alGetBitsFromFormat(format)/8);
	}

	memcpy(scratch.data, data, csamps * (_alGetBitsFromFormat(format)>>3));

	temp = _alBufferCanonizeData(format,
				     scratch.data,
				     csamps,
				     freq,
				     tformat,
				     tfreq,
				     &csize,
				     AL_TRUE);
	if(temp == NULL) {
		/* conversion problem */
		_alDCSetError(AL_OUT_OF_MEMORY);

		_alDebug(ALD_CONVERT, __FILE__, __LINE__,
			"streaming buffer id %d: could not convert",
			buffer);

		return 0;
	}

	/* lock buffer again, as we are about to make changes */
	_alLockBuffer();

	if(buf->size == 0) {
		/* first time: copy data */
		_alDebug(ALD_STREAMING, __FILE__, __LINE__,
			"first time!");

		/* first time */
		buf->size = csize / _alGetChannelsFromFormat(buf->format);

		for(i = 0; i < buf->num_buffers; i++) {
			temp = realloc(buf->orig_buffers[i], csize / _alGetChannelsFromFormat(buf->format));
			if(temp == NULL) {
				_alUnlockBuffer();

				return 0;
			}

			buf->orig_buffers[i] = temp;
		}

		_alMonoify((ALshort **) buf->orig_buffers,
			   scratch.data,
			   csize / _alGetChannelsFromFormat(buf->format),
			   buf->num_buffers, _alGetChannelsFromFormat(buf->format));

		buf->appendpos    = csize;

		_alUnlockBuffer();

		return osamps;
	}

	_alMonoifyOffset((ALshort **) buf->orig_buffers,
			 copyoffset,
			 scratch.data,
			 csize / _alGetChannelsFromFormat(buf->format),
			 buf->num_buffers, _alGetChannelsFromFormat(buf->format));

/*
	offset_memcpy(buf->_orig_buffer, copyoffset, bufferAppendScratch, copysize);
 */

	_alUnlockBuffer();

	return nsamps;
}
Пример #24
0
/*
 * _alcSpeakerInit( ALuint cid )
 *
 * Initialize position wrt listener, w/o rt orientation.
 *
 * assumes locked context
 */
static void _alcSpeakerInit( ALuint cid ) {
    AL_context  *cc;
    AL_listener *lis;
    ALfloat *lpos;
    ALfloat sdis; /* scaled distance */
    ALuint i;
    ALuint num;

    cc  = _alcGetContext( cid );
    lis = _alcGetListener( cid );
    if(cc == NULL) {
        /* invalid cid */
        _alDebug(ALD_CONTEXT, __FILE__, __LINE__,
                 "_alcSpeakerInit: invalid cid 0x%x", cid );

        return;
    }

    if(lis == NULL) {
        /* weird */
        return;
    }

    lpos = lis->position;

    /*
     * A speaker distance of one simplifies the math later.
     */
    sdis = 1.0f;

    _alDebug(ALD_CONTEXT, __FILE__, __LINE__,
             "_alcSpeakerInit: ( sdis %f )", sdis );

    for (i = 0; i < _ALC_MAX_CHANNELS; i++)
    {
        cc->_speaker_pos[i].pos[0]   = lpos[0];
        cc->_speaker_pos[i].pos[1]   = lpos[1];
        cc->_speaker_pos[i].pos[2]   = lpos[2];
    }

    num = _alcGetNumSpeakers(cid);

    /* fourpoint */

    if (num >= 4)
    {
        sdis *= M_SQRT1_2;

        cc->_speaker_pos[ALS_LEFT].pos[2] += sdis;
        cc->_speaker_pos[ALS_RIGHT].pos[2] += sdis;

        cc->_speaker_pos[ALS_LEFTS].pos[0] -= sdis;
        cc->_speaker_pos[ALS_LEFTS].pos[2] -= sdis;

        cc->_speaker_pos[ALS_RIGHTS].pos[0] += sdis;
        cc->_speaker_pos[ALS_RIGHTS].pos[2] -= sdis;
    }

    /* stereo */

    if (num >= 2)
    {
        cc->_speaker_pos[ALS_LEFT].pos[0] -= sdis;
        cc->_speaker_pos[ALS_RIGHT].pos[0] += sdis;
    }
    return;
}