diff options
Diffstat (limited to 'Alc')
-rw-r--r-- | Alc/ALc.c | 24 | ||||
-rw-r--r-- | Alc/ALu.c | 2 | ||||
-rw-r--r-- | Alc/alsa.c | 86 | ||||
-rw-r--r-- | Alc/dsound.c | 130 | ||||
-rw-r--r-- | Alc/oss.c | 49 | ||||
-rw-r--r-- | Alc/wave.c | 335 |
6 files changed, 483 insertions, 143 deletions
@@ -62,6 +62,8 @@ struct { { "winmm", alcWinMMInit, EmptyFuncs }, #endif + { "wave", alc_wave_init, EmptyFuncs }, + { NULL, NULL, EmptyFuncs } }; #undef EmptyFuncs @@ -742,7 +744,7 @@ ALCAPI ALCvoid ALCAPIENTRY alcGetIntegerv(ALCdevice *device,ALCenum param,ALsize data[i++] = device->Frequency; data[i++] = ALC_REFRESH; - data[i++] = device->UpdateFreq; + data[i++] = device->Frequency / device->UpdateFreq; data[i++] = ALC_SYNC; data[i++] = ALC_FALSE; @@ -780,7 +782,7 @@ ALCAPI ALCvoid ALCAPIENTRY alcGetIntegerv(ALCdevice *device,ALCenum param,ALsize else if(!size) SetALCError(ALC_INVALID_VALUE); else - *data = device->UpdateFreq; + *data = device->Frequency / device->UpdateFreq; break; case ALC_SYNC: @@ -792,6 +794,24 @@ ALCAPI ALCvoid ALCAPIENTRY alcGetIntegerv(ALCdevice *device,ALCenum param,ALsize *data = ALC_FALSE; break; + case ALC_MONO_SOURCES: + if(!device || !device->Context) + SetALCError(ALC_INVALID_DEVICE); + else if (size != 1) + SetALCError(ALC_INVALID_VALUE); + else + *data = device->Context->lNumMonoSources; + break; + + case ALC_STEREO_SOURCES: + if(!device || !device->Context) + SetALCError(ALC_INVALID_DEVICE); + else if (size != 1) + SetALCError(ALC_INVALID_VALUE); + else + *data = device->Context->lNumStereoSources; + break; + default: SetALCError(ALC_INVALID_ENUM); break; @@ -151,12 +151,14 @@ __inline ALuint aluChannelsFromFormat(ALenum format) static __inline ALint aluF2L(ALfloat Value) { +#if 0 if(sizeof(ALint) == 4 && sizeof(double) == 8) { double temp; temp = Value + (((65536.0*65536.0*16.0)+(65536.0*65536.0*8.0))*65536.0); return *((ALint*)&temp); } +#endif return (ALint)Value; } @@ -116,7 +116,7 @@ static int xrun_recovery(snd_pcm_t *handle, int err) else if (err == -ESTRPIPE) { while ((err = psnd_pcm_resume(handle)) == -EAGAIN) - usleep(1); /* wait until the suspend flag is released */ + Sleep(1); /* wait until the suspend flag is released */ if (err < 0) { err = psnd_pcm_prepare(handle); @@ -177,7 +177,7 @@ static ALuint ALSAProc(ALvoid *ptr) // make sure there's frames to process if(avail == 0) { - usleep(1000); + Sleep(1); continue; } @@ -222,30 +222,9 @@ static ALuint ALSANoMMapProc(ALvoid *ptr) alsa_data *data = (alsa_data*)pDevice->ExtraData; snd_pcm_sframes_t avail; char *WritePtr; - int err; while(!data->killNow) { - snd_pcm_state_t state = psnd_pcm_state(data->pcmHandle); - if(state == SND_PCM_STATE_XRUN) - { - err = xrun_recovery(data->pcmHandle, -EPIPE); - if (err < 0) - { - AL_PRINT("XRUN recovery failed: %s\n", psnd_strerror(err)); - break; - } - } - else if (state == SND_PCM_STATE_SUSPENDED) - { - err = xrun_recovery(data->pcmHandle, -ESTRPIPE); - if (err < 0) - { - AL_PRINT("SUSPEND recovery failed: %s\n", psnd_strerror(err)); - break; - } - } - SuspendContext(NULL); aluMixData(pDevice->Context, data->buffer, data->size, pDevice->Format); ProcessContext(NULL); @@ -346,6 +325,9 @@ static ALCboolean alsa_open_playback(ALCdevice *device, const ALCchar *deviceNam char *err; int i; + if(!alsa_handle) + return ALC_FALSE; + strncpy(driver, GetConfigValue("alsa", "device", "default"), sizeof(driver)-1); driver[sizeof(driver)-1] = 0; if(deviceName) @@ -385,7 +367,7 @@ open_alsa: i = psnd_pcm_open(&data->pcmHandle, driver, SND_PCM_STREAM_PLAYBACK, SND_PCM_NONBLOCK); if(i < 0) { - usleep(200000); + Sleep(200); i = psnd_pcm_open(&data->pcmHandle, driver, SND_PCM_STREAM_PLAYBACK, SND_PCM_NONBLOCK); } if(i >= 0) @@ -417,7 +399,7 @@ open_alsa: periods = GetConfigValueInt("alsa", "periods", 4); if((int)periods <= 0) periods = 4; - bufferSizeInFrames = device->UpdateFreq; + bufferSizeInFrames = device->UpdateFreq / periods; psnd_pcm_hw_params_malloc(&p); #define ok(func, str) (i=(func),((i<0)?(err=(str)),0:1)) @@ -425,7 +407,7 @@ open_alsa: if(!(ok(psnd_pcm_hw_params_any(data->pcmHandle, p), "any") && /* set interleaved access */ (ok(psnd_pcm_hw_params_set_access(data->pcmHandle, p, SND_PCM_ACCESS_MMAP_INTERLEAVED), "set access") || - ok(psnd_pcm_hw_params_set_access(data->pcmHandle, p, SND_PCM_ACCESS_RW_INTERLEAVED), "set access"))&& + ok(psnd_pcm_hw_params_set_access(data->pcmHandle, p, SND_PCM_ACCESS_RW_INTERLEAVED), "set access")) && /* set format (implicitly sets sample bits) */ ok(psnd_pcm_hw_params_set_format(data->pcmHandle, p, data->format), "set format") && /* set channels (implicitly sets frame bits) */ @@ -461,17 +443,7 @@ open_alsa: device->MaxNoOfSources = 256; device->UpdateFreq = bufferSizeInFrames; - i = psnd_pcm_prepare(data->pcmHandle); - if(i < 0) - { - AL_PRINT("prepare error: %s\n", psnd_strerror(i)); - psnd_pcm_close(data->pcmHandle); - free(data->buffer); - free(data); - return ALC_FALSE; - } - - data->size = psnd_pcm_frames_to_bytes(data->pcmHandle, bufferSizeInFrames); + data->size = psnd_pcm_frames_to_bytes(data->pcmHandle, device->UpdateFreq); if(access == SND_PCM_ACCESS_RW_INTERLEAVED) { data->buffer = malloc(data->size); @@ -484,16 +456,28 @@ open_alsa: } } else + { + i = psnd_pcm_prepare(data->pcmHandle); + if(i < 0) + { + AL_PRINT("prepare error: %s\n", psnd_strerror(i)); + psnd_pcm_close(data->pcmHandle); + free(data->buffer); + free(data); + return ALC_FALSE; + } + fill_silence(data->pcmHandle, data->format, device->Channels); - i = psnd_pcm_start(data->pcmHandle); - if(i < 0) - { - AL_PRINT("start error: %s\n", psnd_strerror(i)); - psnd_pcm_close(data->pcmHandle); - free(data->buffer); - free(data); - return ALC_FALSE; + i = psnd_pcm_start(data->pcmHandle); + if(i < 0) + { + AL_PRINT("start error: %s\n", psnd_strerror(i)); + psnd_pcm_close(data->pcmHandle); + free(data->buffer); + free(data); + return ALC_FALSE; + } } device->ExtraData = data; @@ -531,12 +515,15 @@ static ALCboolean alsa_open_capture(ALCdevice *pDevice, const ALCchar *deviceNam snd_pcm_format_t alsaFormat; snd_pcm_hw_params_t *p; unsigned int periods = 4; - snd_pcm_uframes_t bufferSizeInFrames = SampleSize; + snd_pcm_uframes_t bufferSizeInFrames; alsa_data *data; char driver[64]; char *err; int i; + if(!alsa_handle) + return ALC_FALSE; + strncpy(driver, GetConfigValue("alsa", "capture", "default"), sizeof(driver)-1); driver[sizeof(driver)-1] = 0; if(deviceName) @@ -565,7 +552,7 @@ open_alsa: i = psnd_pcm_open(&data->pcmHandle, driver, SND_PCM_STREAM_CAPTURE, SND_PCM_NONBLOCK); if(i < 0) { - usleep(200000); + Sleep(200); i = psnd_pcm_open(&data->pcmHandle, driver, SND_PCM_STREAM_CAPTURE, SND_PCM_NONBLOCK); } if(i >= 0) @@ -594,6 +581,8 @@ open_alsa: AL_PRINT("Unknown format?! %x\n", format); } + bufferSizeInFrames = SampleSize / periods; + psnd_pcm_hw_params_malloc(&p); #define ok(func, str) (i=(func),((i<0)?(err=(str)),0:1)) /* start with the largest configuration space possible */ @@ -775,7 +764,7 @@ void alc_alsa_init(BackendFuncs *func_list) } while(0) #else str = NULL; - alsa_handle = NULL; + alsa_handle = 0xDEADBEEF; #define LOAD_FUNC(f) p##f = f #endif @@ -910,7 +899,6 @@ next_card: } if (err >= 0 && (err = psnd_ctl_card_info(handle, info)) < 0) { AL_PRINT("control hardware info (%i): %s\n", card, psnd_strerror(err)); - psnd_ctl_close(handle); } else if (err >= 0 && card < MAX_DEVICES-1) { diff --git a/Alc/dsound.c b/Alc/dsound.c index 90a422a2..d2708f0a 100644 --- a/Alc/dsound.c +++ b/Alc/dsound.c @@ -36,71 +36,74 @@ typedef struct { LPDIRECTSOUND lpDS; LPDIRECTSOUNDBUFFER DSpbuffer; LPDIRECTSOUNDBUFFER DSsbuffer; - MMRESULT ulDSTimerID; - DWORD OldWriteCursor; + + int killNow; + ALvoid *thread; } DSoundData; static ALCchar *DeviceList[16]; -static void CALLBACK DirectSoundProc(UINT uID,UINT uReserved,DWORD_PTR dwUser,DWORD_PTR dwReserved1,DWORD_PTR dwReserved2) -{ - ALCdevice *pDevice = (ALCdevice *)dwUser; - DSoundData *pData = pDevice->ExtraData; - DWORD PlayCursor,WriteCursor; - BYTE *WritePtr1,*WritePtr2; - DWORD WriteCnt1,WriteCnt2; - WAVEFORMATEX OutputType; - DWORD BytesPlayed; - DWORD BufSize; - HRESULT DSRes; - (void)uID; - (void)uReserved; - (void)dwReserved1; - (void)dwReserved2; +static ALuint DSoundProc(ALvoid *ptr) +{ + ALCdevice *pDevice = (ALCdevice*)ptr; + DSoundData *pData = (DSoundData*)pDevice->ExtraData; + DWORD LastCursor = 0; + DWORD PlayCursor; + VOID *WritePtr; + DWORD WriteCnt; + DWORD avail; + HRESULT err; + + while(!pData->killNow) + { + // Get current play and write cursors + IDirectSoundBuffer_GetCurrentPosition(pData->DSsbuffer, &PlayCursor, NULL); + avail = (PlayCursor-LastCursor) % (pDevice->UpdateFreq*pDevice->FrameSize); - BufSize = pDevice->UpdateFreq * pDevice->FrameSize; + if(avail == 0) + { + Sleep(1); + continue; + } - // Get current play and write cursors - IDirectSoundBuffer_GetCurrentPosition(pData->DSsbuffer,&PlayCursor,&WriteCursor); - if (!pData->OldWriteCursor) pData->OldWriteCursor=WriteCursor-PlayCursor; + // Lock output buffer + WriteCnt = 0; + err = IDirectSoundBuffer_Lock(pData->DSsbuffer, LastCursor, avail, &WritePtr, &WriteCnt, NULL, NULL, 0); - // Get the output format and figure the number of bytes played (block aligned) - IDirectSoundBuffer_GetFormat(pData->DSsbuffer,&OutputType,sizeof(WAVEFORMATEX),NULL); - BytesPlayed=((((WriteCursor<pData->OldWriteCursor)?(BufSize+WriteCursor-pData->OldWriteCursor):(WriteCursor-pData->OldWriteCursor))/OutputType.nBlockAlign)*OutputType.nBlockAlign); + // If the buffer is lost, restore it, play and lock + if(err == DSERR_BUFFERLOST) + { + err = IDirectSoundBuffer_Restore(pData->DSsbuffer); + if(SUCCEEDED(err)) + err = IDirectSoundBuffer_Play(pData->DSsbuffer, 0, 0, DSBPLAY_LOOPING); + if(SUCCEEDED(err)) + err = IDirectSoundBuffer_Lock(pData->DSsbuffer, LastCursor, avail, (LPVOID*)&WritePtr, &WriteCnt, NULL, NULL, 0); + } - // Lock output buffer started at 40msec in front of the old write cursor (15msec in front of the actual write cursor) - DSRes=IDirectSoundBuffer_Lock(pData->DSsbuffer,(pData->OldWriteCursor+(OutputType.nSamplesPerSec/25)*OutputType.nBlockAlign)%BufSize,BytesPlayed,(LPVOID*)&WritePtr1,&WriteCnt1,(LPVOID*)&WritePtr2,&WriteCnt2,0); + // Successfully locked the output buffer + if(SUCCEEDED(err)) + { + // If we have an active context, mix data directly into output buffer otherwise fill with silence + SuspendContext(NULL); + aluMixData(pDevice->Context, WritePtr, WriteCnt, pDevice->Format); + ProcessContext(NULL); - // If the buffer is lost, restore it, play and lock - if (DSRes==DSERR_BUFFERLOST) - { - IDirectSoundBuffer_Restore(pData->DSsbuffer); - IDirectSoundBuffer_Play(pData->DSsbuffer,0,0,DSBPLAY_LOOPING); - DSRes=IDirectSoundBuffer_Lock(pData->DSsbuffer,(pData->OldWriteCursor+(OutputType.nSamplesPerSec/25)*OutputType.nBlockAlign)%BufSize,BytesPlayed,(LPVOID*)&WritePtr1,&WriteCnt1,(LPVOID*)&WritePtr2,&WriteCnt2,0); - } + // Unlock output buffer only when successfully locked + IDirectSoundBuffer_Unlock(pData->DSsbuffer, WritePtr, WriteCnt, NULL, 0); + } + else + AL_PRINT("Buffer lock error: %#lx\n", err); - // Successfully locked the output buffer - if (DSRes==DS_OK) - { - // If we have an active context, mix data directly into output buffer otherwise fill with silence - SuspendContext(NULL); - if (WritePtr1) - aluMixData(pDevice->Context, WritePtr1, WriteCnt1, pDevice->Format); - if (WritePtr2) - aluMixData(pDevice->Context, WritePtr2, WriteCnt2, pDevice->Format); - ProcessContext(NULL); - - // Unlock output buffer only when successfully locked - IDirectSoundBuffer_Unlock(pData->DSsbuffer,WritePtr1,WriteCnt1,WritePtr2,WriteCnt2); + // Update old write cursor location + LastCursor += WriteCnt; + LastCursor %= pDevice->UpdateFreq*pDevice->FrameSize; } - // Update old write cursor location - pData->OldWriteCursor=((pData->OldWriteCursor+BytesPlayed)%BufSize); + return 0; } - static ALCboolean DSoundOpenPlayback(ALCdevice *device, const ALCchar *deviceName) { DSBUFFERDESC DSBDescription; @@ -177,6 +180,13 @@ static ALCboolean DSoundOpenPlayback(ALCdevice *device, const ALCchar *deviceNam if(SUCCEEDED(hr)) hr = IDirectSoundBuffer_Play(pData->DSsbuffer, 0, 0, DSBPLAY_LOOPING); + device->MaxNoOfSources = 256; + device->ExtraData = pData; + + pData->thread = StartThread(DSoundProc, device); + if(!pData->thread) + hr = E_FAIL; + if(FAILED(hr)) { if (pData->DSsbuffer) @@ -190,10 +200,6 @@ static ALCboolean DSoundOpenPlayback(ALCdevice *device, const ALCchar *deviceNam return ALC_FALSE; } - pData->ulDSTimerID = timeSetEvent(25, 0, (LPTIMECALLBACK)DirectSoundProc, (DWORD)device, (UINT)TIME_CALLBACK_FUNCTION|TIME_PERIODIC); - device->MaxNoOfSources = 256; - - device->ExtraData = pData; return ALC_TRUE; } @@ -201,26 +207,16 @@ static void DSoundClosePlayback(ALCdevice *device) { DSoundData *pData = device->ExtraData; - // Stop and release the DS timer - if (pData->ulDSTimerID) - timeKillEvent(pData->ulDSTimerID); + pData->killNow = 1; + StopThread(pData->thread); - // Wait ... just in case any timer events happen - Sleep(100); - - SuspendContext(NULL); - - if (pData->DSsbuffer) - IDirectSoundBuffer_Release(pData->DSsbuffer); - if (pData->DSpbuffer) - IDirectSoundBuffer_Release(pData->DSpbuffer); + IDirectSoundBuffer_Release(pData->DSsbuffer); + IDirectSoundBuffer_Release(pData->DSpbuffer); IDirectSound_Release(pData->lpDS); //Deinit COM CoUninitialize(); - ProcessContext(NULL); - free(pData); device->ExtraData = NULL; } @@ -55,7 +55,6 @@ typedef struct { ALubyte *mix_data; int data_size; - int silence; RingBuffer *ring; int doCapture; @@ -78,31 +77,35 @@ static ALuint OSSProc(ALvoid *ptr) { ALCdevice *pDevice = (ALCdevice*)ptr; oss_data *data = (oss_data*)pDevice->ExtraData; - int remaining; + int remaining = 0; int wrote; while(!data->killNow) { - SuspendContext(NULL); - aluMixData(pDevice->Context,data->mix_data,data->data_size,pDevice->Format); - ProcessContext(NULL); + int len = data->data_size - remaining; - remaining = data->data_size; - while(remaining > 0) + if(len > 0) + { + SuspendContext(NULL); + aluMixData(pDevice->Context, data->mix_data+remaining, len, pDevice->Format); + ProcessContext(NULL); + } + + remaining += len; + wrote = write(data->fd, data->mix_data, remaining); + if(wrote < 0) + { + AL_PRINT("write failed: %s\n", strerror(errno)); + remaining = 0; + } + else if(wrote > 0) { - wrote = write(data->fd, data->mix_data+data->data_size-remaining, remaining); - if(wrote < 0) - { - AL_PRINT("write failed: %s\n", strerror(errno)); - break; - } - if(wrote == 0) - { - usleep(1000); - continue; - } remaining -= wrote; + if(remaining > 0) + memmove(data->mix_data, data->mix_data+wrote, remaining); } + else + Sleep(1); } return 0; @@ -128,7 +131,7 @@ static ALuint OSSCaptureProc(ALvoid *ptr) } if(amt == 0) { - usleep(1000); + Sleep(1); continue; } if(data->doCapture) @@ -177,11 +180,9 @@ static ALCboolean oss_open_playback(ALCdevice *device, const ALCchar *deviceName switch(aluBytesFromFormat(device->Format)) { case 1: - data->silence = 0x80; ossFormat = AFMT_U8; break; case 2: - data->silence = 0; ossFormat = AFMT_S16_NE; break; default: @@ -190,7 +191,7 @@ static ALCboolean oss_open_playback(ALCdevice *device, const ALCchar *deviceName } periods = GetConfigValueInt("oss", "periods", 4); - if((int)periods < 0) + if((int)periods <= 0) periods = 4; numChannels = device->Channels; ossSpeed = device->Frequency; @@ -307,11 +308,9 @@ static ALCboolean oss_open_capture(ALCdevice *device, const ALCchar *deviceName, switch(aluBytesFromFormat(format)) { case 1: - data->silence = 0x80; ossFormat = AFMT_U8; break; case 2: - data->silence = 0; ossFormat = AFMT_S16_NE; break; default: @@ -402,7 +401,7 @@ static ALCboolean oss_open_capture(ALCdevice *device, const ALCchar *deviceName, device->UpdateFreq = info.fragsize / device->FrameSize; - data->data_size = device->UpdateFreq * device->FrameSize; + data->data_size = device->UpdateFreq * device->FrameSize * info.fragments; data->mix_data = calloc(1, data->data_size); device->ExtraData = data; diff --git a/Alc/wave.c b/Alc/wave.c new file mode 100644 index 00000000..de4c87db --- /dev/null +++ b/Alc/wave.c @@ -0,0 +1,335 @@ +/** + * OpenAL cross platform audio library + * Copyright (C) 1999-2007 by authors. + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + * Or go to http://www.gnu.org/copyleft/lgpl.html + */ + +#include "config.h" + +#include <stdlib.h> +#include <stdio.h> +#include <memory.h> +#include "alMain.h" +#include "AL/al.h" +#include "AL/alc.h" + + +typedef struct { + FILE *f; + long DataStart; + + ALvoid *buffer; + ALuint size; + + int killNow; + ALvoid *thread; +} wave_data; + + +static ALCchar *waveDevice; + + +static ALuint WaveProc(ALvoid *ptr) +{ + ALCdevice *pDevice = (ALCdevice*)ptr; + wave_data *data = (wave_data*)pDevice->ExtraData; + ALuint frameSize; + ALuint now, last; + size_t WriteCnt; + ALuint avail; + union { + short s; + char b[sizeof(short)]; + } uSB; + + uSB.s = 1; + frameSize = aluBytesFromFormat(pDevice->Format) * + aluChannelsFromFormat(pDevice->Format); + + last = timeGetTime(); + while(!data->killNow) + { + now = timeGetTime(); + + avail = (now-last) * pDevice->Frequency / 1000; + if(avail < pDevice->UpdateFreq/4) + { + Sleep(1); + continue; + } + + while(avail > 0) + { + SuspendContext(NULL); + WriteCnt = min(data->size, avail); + aluMixData(pDevice->Context, data->buffer, WriteCnt * frameSize, + pDevice->Format); + ProcessContext(NULL); + + if(uSB.b[0] != 1 && aluBytesFromFormat(pDevice->Format) > 1) + { + ALubyte *bytes = data->buffer; + ALuint i; + + for(i = 0;i < WriteCnt*frameSize;i++) + fputc(bytes[i^1], data->f); + } + else + fwrite(data->buffer, frameSize, WriteCnt, data->f); + if(ferror(data->f)) + { + AL_PRINT("Error writing to file\n"); + data->killNow = 1; + break; + } + + avail -= WriteCnt; + } + last = now; + } + + return 0; +} + +static ALCboolean wave_open_playback(ALCdevice *device, const ALCchar *deviceName) +{ + wave_data *data; + ALuint channels; + ALuint bits; + const char *fname; + int i; + + fname = GetConfigValue("wave", "file", ""); + if(!fname[0]) + return ALC_FALSE; + + if(deviceName) + { + if(strcmp(deviceName, waveDevice) != 0) + return ALC_FALSE; + device->szDeviceName = waveDevice; + } + else + device->szDeviceName = waveDevice; + + data = (wave_data*)calloc(1, sizeof(wave_data)); + + data->f = fopen(fname, "wb"); + if(!data->f) + { + free(data); + AL_PRINT("Could not open file '%s': %s\n", fname, strerror(errno)); + return ALC_FALSE; + } + + bits = aluBytesFromFormat(device->Format) * 8; + channels = aluChannelsFromFormat(device->Format); + switch(bits) + { + case 8: + case 16: + if(channels == 0) + { + AL_PRINT("Unknown format?! %x\n", device->Format); + fclose(data->f); + free(data); + return ALC_FALSE; + } + break; + + default: + AL_PRINT("Unknown format?! %x\n", device->Format); + fclose(data->f); + free(data); + return ALC_FALSE; + } + + fprintf(data->f, "RIFF"); + fputc(0, data->f); // 'RIFF' header len; filled in at close + fputc(0, data->f); + fputc(0, data->f); + fputc(0, data->f); + + fprintf(data->f, "WAVE"); + + fprintf(data->f, "fmt "); + fputc(16, data->f); // 'fmt ' header len; 16 bytes for PCM + fputc(0, data->f); + fputc(0, data->f); + fputc(0, data->f); + // 16-bit val, format type id (PCM: 1) + fputc(1, data->f); + fputc(0, data->f); + // 16-bit val, channel count + fputc(channels&0xff, data->f); + fputc((channels>>8)&0xff, data->f); + // 32-bit val, frequency + fputc(device->Frequency&0xff, data->f); + fputc((device->Frequency>>8)&0xff, data->f); + fputc((device->Frequency>>16)&0xff, data->f); + fputc((device->Frequency>>24)&0xff, data->f); + // 32-bit val, bytes per second + i = device->Frequency * channels * bits / 8; + fputc(i&0xff, data->f); + fputc((i>>8)&0xff, data->f); + fputc((i>>16)&0xff, data->f); + fputc((i>>24)&0xff, data->f); + // 16-bit val, frame size + i = channels * bits / 8; + fputc(i&0xff, data->f); + fputc((i>>8)&0xff, data->f); + // 16-bit val, bits per sample + fputc(bits&0xff, data->f); + fputc((bits>>8)&0xff, data->f); + + fprintf(data->f, "data"); + fputc(0, data->f); // 'data' header len; filled in at close + fputc(0, data->f); + fputc(0, data->f); + fputc(0, data->f); + + if(ferror(data->f)) + { + AL_PRINT("Error writing header: %s\n", strerror(errno)); + fclose(data->f); + free(data); + return ALC_FALSE; + } + + data->DataStart = ftell(data->f); + + device->MaxNoOfSources = 256; + device->UpdateFreq = max(device->UpdateFreq, 2048); + + data->size = device->UpdateFreq; + data->buffer = malloc(data->size * channels * bits / 8); + if(!data->buffer) + { + AL_PRINT("buffer malloc failed\n"); + fclose(data->f); + free(data); + return ALC_FALSE; + } + + device->ExtraData = data; + data->thread = StartThread(WaveProc, device); + if(data->thread == NULL) + { + device->ExtraData = NULL; + fclose(data->f); + free(data->buffer); + free(data); + return ALC_FALSE; + } + + return ALC_TRUE; +} + +static void wave_close_playback(ALCdevice *device) +{ + wave_data *data = (wave_data*)device->ExtraData; + ALuint dataLen; + long size; + + data->killNow = 1; + StopThread(data->thread); + + size = ftell(data->f); + if(size > 0) + { + dataLen = size - data->DataStart; + if(fseek(data->f, data->DataStart-4, SEEK_SET) == 0) + { + fputc(dataLen&0xff, data->f); // 'data' header len + fputc((dataLen>>8)&0xff, data->f); + fputc((dataLen>>16)&0xff, data->f); + fputc((dataLen>>24)&0xff, data->f); + } + if(fseek(data->f, 4, SEEK_SET) == 0) + { + size -= 8; + fputc(size&0xff, data->f); // 'WAVE' header len + fputc((size>>8)&0xff, data->f); + fputc((size>>16)&0xff, data->f); + fputc((size>>24)&0xff, data->f); + } + } + + fclose(data->f); + free(data->buffer); + free(data); + device->ExtraData = NULL; +} + + +static ALCboolean wave_open_capture(ALCdevice *pDevice, const ALCchar *deviceName, ALCuint frequency, ALCenum format, ALCsizei SampleSize) +{ + (void)pDevice; + (void)deviceName; + (void)frequency; + (void)format; + (void)SampleSize; + return ALC_FALSE; +} + +static void wave_close_capture(ALCdevice *pDevice) +{ + (void)pDevice; +} + +static void wave_start_capture(ALCdevice *pDevice) +{ + (void)pDevice; +} + +static void wave_stop_capture(ALCdevice *pDevice) +{ + (void)pDevice; +} + +static void wave_capture_samples(ALCdevice *pDevice, ALCvoid *pBuffer, ALCuint lSamples) +{ + (void)pDevice; + (void)pBuffer; + (void)lSamples; +} + +static ALCuint wave_available_samples(ALCdevice *pDevice) +{ + (void)pDevice; + return 0; +} + + +BackendFuncs wave_funcs = { + wave_open_playback, + wave_close_playback, + wave_open_capture, + wave_close_capture, + wave_start_capture, + wave_stop_capture, + wave_capture_samples, + wave_available_samples +}; + +void alc_wave_init(BackendFuncs *func_list) +{ + *func_list = wave_funcs; + + waveDevice = AppendDeviceList("Wave File Writer"); + AppendAllDeviceList(waveDevice); +} |