static ALCenum WinMMOpenPlayback(ALCdevice *Device, const ALCchar *deviceName) { WinMMData *data = NULL; const al_string *iter, *end; UINT DeviceID; MMRESULT res; if(VECTOR_SIZE(PlaybackDevices) == 0) ProbePlaybackDevices(); // Find the Device ID matching the deviceName if valid iter = VECTOR_ITER_BEGIN(PlaybackDevices); end = VECTOR_ITER_END(PlaybackDevices); for(; iter != end; iter++) { if(!al_string_empty(*iter) && (!deviceName || al_string_cmp_cstr(*iter, deviceName) == 0)) { DeviceID = (UINT)(iter - VECTOR_ITER_BEGIN(PlaybackDevices)); break; } } if(iter == end) return ALC_INVALID_VALUE; data = calloc(1, sizeof(*data)); if(!data) return ALC_OUT_OF_MEMORY; Device->ExtraData = data; retry_open: memset(&data->Format, 0, sizeof(WAVEFORMATEX)); if(Device->FmtType == DevFmtFloat) { data->Format.wFormatTag = WAVE_FORMAT_IEEE_FLOAT; data->Format.wBitsPerSample = 32; } else { data->Format.wFormatTag = WAVE_FORMAT_PCM; if(Device->FmtType == DevFmtUByte || Device->FmtType == DevFmtByte) data->Format.wBitsPerSample = 8; else data->Format.wBitsPerSample = 16; } data->Format.nChannels = ((Device->FmtChans == DevFmtMono) ? 1 : 2); data->Format.nBlockAlign = data->Format.wBitsPerSample * data->Format.nChannels / 8; data->Format.nSamplesPerSec = Device->Frequency; data->Format.nAvgBytesPerSec = data->Format.nSamplesPerSec * data->Format.nBlockAlign; data->Format.cbSize = 0; if((res=waveOutOpen(&data->WaveHandle.Out, DeviceID, &data->Format, (DWORD_PTR)&WaveOutProc, (DWORD_PTR)Device, CALLBACK_FUNCTION)) != MMSYSERR_NOERROR) { if(Device->FmtType == DevFmtFloat) { Device->FmtType = DevFmtShort; goto retry_open; } ERR("waveOutOpen failed: %u\n", res); goto failure; } al_string_copy(&Device->DeviceName, VECTOR_ELEM(PlaybackDevices, DeviceID)); return ALC_NO_ERROR; failure: if(data->WaveHandle.Out) waveOutClose(data->WaveHandle.Out); free(data); Device->ExtraData = NULL; return ALC_INVALID_VALUE; }
static ALCenum WinMMOpenCapture(ALCdevice *Device, const ALCchar *deviceName) { const al_string *iter, *end; ALbyte *BufferData = NULL; DWORD CapturedDataSize; WinMMData *data = NULL; ALint BufferSize; UINT DeviceID; MMRESULT res; ALuint i; if(VECTOR_SIZE(CaptureDevices) == 0) ProbeCaptureDevices(); // Find the Device ID matching the deviceName if valid iter = VECTOR_ITER_BEGIN(CaptureDevices); end = VECTOR_ITER_END(CaptureDevices); for(; iter != end; iter++) { if(!al_string_empty(*iter) && (!deviceName || al_string_cmp_cstr(*iter, deviceName) == 0)) { DeviceID = (UINT)(iter - VECTOR_ITER_BEGIN(CaptureDevices)); break; } } if(iter == end) return ALC_INVALID_VALUE; switch(Device->FmtChans) { case DevFmtMono: case DevFmtStereo: break; case DevFmtQuad: case DevFmtX51: case DevFmtX51Side: case DevFmtX61: case DevFmtX71: return ALC_INVALID_ENUM; } switch(Device->FmtType) { case DevFmtUByte: case DevFmtShort: case DevFmtInt: case DevFmtFloat: break; case DevFmtByte: case DevFmtUShort: case DevFmtUInt: return ALC_INVALID_ENUM; } data = calloc(1, sizeof(*data)); if(!data) return ALC_OUT_OF_MEMORY; Device->ExtraData = data; memset(&data->Format, 0, sizeof(WAVEFORMATEX)); data->Format.wFormatTag = ((Device->FmtType == DevFmtFloat) ? WAVE_FORMAT_IEEE_FLOAT : WAVE_FORMAT_PCM); data->Format.nChannels = ChannelsFromDevFmt(Device->FmtChans); data->Format.wBitsPerSample = BytesFromDevFmt(Device->FmtType) * 8; data->Format.nBlockAlign = data->Format.wBitsPerSample * data->Format.nChannels / 8; data->Format.nSamplesPerSec = Device->Frequency; data->Format.nAvgBytesPerSec = data->Format.nSamplesPerSec * data->Format.nBlockAlign; data->Format.cbSize = 0; if((res=waveInOpen(&data->WaveHandle.In, DeviceID, &data->Format, (DWORD_PTR)&WaveInProc, (DWORD_PTR)Device, CALLBACK_FUNCTION)) != MMSYSERR_NOERROR) { ERR("waveInOpen failed: %u\n", res); goto failure; } // Allocate circular memory buffer for the captured audio CapturedDataSize = Device->UpdateSize*Device->NumUpdates; // Make sure circular buffer is at least 100ms in size if(CapturedDataSize < (data->Format.nSamplesPerSec / 10)) CapturedDataSize = data->Format.nSamplesPerSec / 10; data->Ring = CreateRingBuffer(data->Format.nBlockAlign, CapturedDataSize); if(!data->Ring) goto failure; InitRef(&data->WaveBuffersCommitted, 0); // Create 4 Buffers of 50ms each BufferSize = data->Format.nAvgBytesPerSec / 20; BufferSize -= (BufferSize % data->Format.nBlockAlign); BufferData = calloc(4, BufferSize); if(!BufferData) goto failure; for(i = 0; i < 4; i++) { memset(&data->WaveBuffer[i], 0, sizeof(WAVEHDR)); data->WaveBuffer[i].dwBufferLength = BufferSize; data->WaveBuffer[i].lpData = ((i==0) ? (CHAR*)BufferData : (data->WaveBuffer[i-1].lpData + data->WaveBuffer[i-1].dwBufferLength)); data->WaveBuffer[i].dwFlags = 0; data->WaveBuffer[i].dwLoops = 0; waveInPrepareHeader(data->WaveHandle.In, &data->WaveBuffer[i], sizeof(WAVEHDR)); waveInAddBuffer(data->WaveHandle.In, &data->WaveBuffer[i], sizeof(WAVEHDR)); IncrementRef(&data->WaveBuffersCommitted); } if(althrd_create(&data->thread, CaptureThreadProc, Device) != althrd_success) goto failure; al_string_copy(&Device->DeviceName, VECTOR_ELEM(CaptureDevices, DeviceID)); return ALC_NO_ERROR; failure: if(BufferData) { for(i = 0; i < 4; i++) waveInUnprepareHeader(data->WaveHandle.In, &data->WaveBuffer[i], sizeof(WAVEHDR)); free(BufferData); } if(data->Ring) DestroyRingBuffer(data->Ring); if(data->WaveHandle.In) waveInClose(data->WaveHandle.In); free(data); Device->ExtraData = NULL; return ALC_INVALID_VALUE; }
void aluInitRenderer(ALCdevice *device, ALint hrtf_id, enum HrtfRequestMode hrtf_appreq, enum HrtfRequestMode hrtf_userreq) { const char *mode; bool headphones; int bs2blevel; size_t i; device->Hrtf = NULL; al_string_clear(&device->Hrtf_Name); device->Render_Mode = NormalRender; memset(&device->Dry.Ambi, 0, sizeof(device->Dry.Ambi)); device->Dry.CoeffCount = 0; device->Dry.NumChannels = 0; if(device->FmtChans != DevFmtStereo) { ALuint speakermap[MAX_OUTPUT_CHANNELS]; const char *devname, *layout = NULL; AmbDecConf conf, *pconf = NULL; if(hrtf_appreq == Hrtf_Enable) device->Hrtf_Status = ALC_HRTF_UNSUPPORTED_FORMAT_SOFT; ambdec_init(&conf); devname = al_string_get_cstr(device->DeviceName); switch(device->FmtChans) { case DevFmtQuad: layout = "quad"; break; case DevFmtX51: layout = "surround51"; break; case DevFmtX51Rear: layout = "surround51rear"; break; case DevFmtX61: layout = "surround61"; break; case DevFmtX71: layout = "surround71"; break; /* Mono, Stereo, and B-Fornat output don't use custom decoders. */ case DevFmtMono: case DevFmtStereo: case DevFmtBFormat3D: break; } if(layout) { const char *fname; if(ConfigValueStr(devname, "decoder", layout, &fname)) { if(!ambdec_load(&conf, fname)) ERR("Failed to load layout file %s\n", fname); else { if(conf.ChanMask > 0xffff) ERR("Unsupported channel mask 0x%04x (max 0xffff)\n", conf.ChanMask); else { if(MakeSpeakerMap(device, &conf, speakermap)) pconf = &conf; } } } } if(pconf && GetConfigValueBool(devname, "decoder", "hq-mode", 0)) { if(!device->AmbiDecoder) device->AmbiDecoder = bformatdec_alloc(); } else { bformatdec_free(device->AmbiDecoder); device->AmbiDecoder = NULL; } if(!pconf) InitPanning(device); else if(device->AmbiDecoder) InitHQPanning(device, pconf, speakermap); else InitCustomPanning(device, pconf, speakermap); ambdec_deinit(&conf); return; } bformatdec_free(device->AmbiDecoder); device->AmbiDecoder = NULL; headphones = device->IsHeadphones; if(device->Type != Loopback) { const char *mode; if(ConfigValueStr(al_string_get_cstr(device->DeviceName), NULL, "stereo-mode", &mode)) { if(strcasecmp(mode, "headphones") == 0) headphones = true; else if(strcasecmp(mode, "speakers") == 0) headphones = false; else if(strcasecmp(mode, "auto") != 0) ERR("Unexpected stereo-mode: %s\n", mode); } } if(hrtf_userreq == Hrtf_Default) { bool usehrtf = (headphones && hrtf_appreq != Hrtf_Disable) || (hrtf_appreq == Hrtf_Enable); if(!usehrtf) goto no_hrtf; device->Hrtf_Status = ALC_HRTF_ENABLED_SOFT; if(headphones && hrtf_appreq != Hrtf_Disable) device->Hrtf_Status = ALC_HRTF_HEADPHONES_DETECTED_SOFT; } else { if(hrtf_userreq != Hrtf_Enable) { if(hrtf_appreq == Hrtf_Enable) device->Hrtf_Status = ALC_HRTF_DENIED_SOFT; goto no_hrtf; } device->Hrtf_Status = ALC_HRTF_REQUIRED_SOFT; } if(VECTOR_SIZE(device->Hrtf_List) == 0) { VECTOR_DEINIT(device->Hrtf_List); device->Hrtf_List = EnumerateHrtf(device->DeviceName); } if(hrtf_id >= 0 && (size_t)hrtf_id < VECTOR_SIZE(device->Hrtf_List)) { const HrtfEntry *entry = &VECTOR_ELEM(device->Hrtf_List, hrtf_id); if(GetHrtfSampleRate(entry->hrtf) == device->Frequency) { device->Hrtf = entry->hrtf; al_string_copy(&device->Hrtf_Name, entry->name); } } for(i = 0;!device->Hrtf && i < VECTOR_SIZE(device->Hrtf_List);i++) { const HrtfEntry *entry = &VECTOR_ELEM(device->Hrtf_List, i); if(GetHrtfSampleRate(entry->hrtf) == device->Frequency) { device->Hrtf = entry->hrtf; al_string_copy(&device->Hrtf_Name, entry->name); } } if(device->Hrtf) { device->Render_Mode = HrtfRender; if(ConfigValueStr(al_string_get_cstr(device->DeviceName), NULL, "hrtf-mode", &mode)) { if(strcasecmp(mode, "full") == 0) device->Render_Mode = HrtfRender; else if(strcasecmp(mode, "basic") == 0) device->Render_Mode = NormalRender; else ERR("Unexpected hrtf-mode: %s\n", mode); } TRACE("HRTF enabled, \"%s\"\n", al_string_get_cstr(device->Hrtf_Name)); InitHrtfPanning(device); return; } device->Hrtf_Status = ALC_HRTF_UNSUPPORTED_FORMAT_SOFT; no_hrtf: TRACE("HRTF disabled\n"); bs2blevel = ((headphones && hrtf_appreq != Hrtf_Disable) || (hrtf_appreq == Hrtf_Enable)) ? 5 : 0; if(device->Type != Loopback) ConfigValueInt(al_string_get_cstr(device->DeviceName), NULL, "cf_level", &bs2blevel); if(bs2blevel > 0 && bs2blevel <= 6) { device->Bs2b = al_calloc(16, sizeof(*device->Bs2b)); bs2b_set_params(device->Bs2b, bs2blevel, device->Frequency); device->Render_Mode = StereoPair; TRACE("BS2B enabled\n"); InitPanning(device); return; } TRACE("BS2B disabled\n"); device->Render_Mode = NormalRender; if(ConfigValueStr(al_string_get_cstr(device->DeviceName), NULL, "stereo-panning", &mode)) { if(strcasecmp(mode, "paired") == 0) device->Render_Mode = StereoPair; else if(strcasecmp(mode, "uhj") != 0) ERR("Unexpected stereo-panning: %s\n", mode); } if(device->Render_Mode == NormalRender) { device->Uhj_Encoder = al_calloc(16, sizeof(Uhj2Encoder)); TRACE("UHJ enabled\n"); InitUhjPanning(device); return; } TRACE("UHJ disabled\n"); InitPanning(device); }