static inline ALeffectslot *LookupEffectSlot(ALCcontext *context, ALuint id) { id--; if(UNLIKELY(id >= VECTOR_SIZE(context->EffectSlotList))) return NULL; return VECTOR_ELEM(context->EffectSlotList, id); }
void open_new_tsb(char *name, int lineno) { int new_index; tsb_t *tsb; int i; int exists_error = 0; if(get_tsb_ptr_by_name(name)) { exists_error = 1; /* Defer error until after object is created to use standard error handlers */ } new_index = add_vector_elements(&Tsb_vector, 1); Open_tsb_index = new_index; tsb = VECTOR_ELEM(Tsb_vector, new_index, tsb_vector_el_t); tsb->name = strdup(name); tsb->lineno = lineno; if(exists_error) { gf_error(M_BADTSB, FLINE_f "TSB named '%s' already exists!\n", SRC_FLINE(tsb), name); } }
void tsb_link_add_entry(tsb_link_t *tsb_link, uint64_t tag, uint64_t data, tsb_entry_t *tsb_entry, block_t *block, block_tsb_t *block_tsb) { tsb_link_entry_t *link_entry; if(tsb_entry->tag == TSB_LINK_TAG) { uint64_t index; /* add to chain */ index = (tsb_entry->data - tsb_link->start_addr) / LINK_SIZE; link_entry = VECTOR_ELEM(tsb_link->entries, index, tsb_link_entry_vector_el_t); /* chase to the end of the chain */ while(link_entry->next) { if((link_entry->tag == tag) && !Suppress_dup_tags_error) { gf_error(M_DUPLICATETAG, "Conflict in TSB_Link '%s'.\n" "Tag 0x%llx being added twice.\n" FLINE_f "First from block '%s'\n" FLINE_f "Again from block '%s'\n", tsb_link->name, tag, SRC_FLINE(link_entry->block), link_entry->block->name, SRC_FLINE(block), block->name); } link_entry = link_entry->next; } add_to_chain(tsb_link, link_entry, tag, data, block, block_tsb); } else { /* create new chain */ link_entry = start_new_chain(tsb_link, tsb_entry->tag, tsb_entry->data, block, block_tsb); add_to_chain(tsb_link, link_entry, tag, data, block, block_tsb); if((link_entry->tag == tag) && !Suppress_dup_tags_error) { gf_error(M_DUPLICATETAG, "Conflict in TSB_Link '%s'.\n" "Tag 0x%llx being added twice.\n" FLINE_f "First from block '%s'\n" FLINE_f "Again from block '%s'\n", tsb_link->name, tag, SRC_FLINE(tsb_entry->block), tsb_entry->block->name, SRC_FLINE(block), block->name); } tsb_entry->tag = TSB_LINK_TAG; tsb_entry->data = link_entry->my_link; } }
static void FreeEffect(ALCdevice *device, ALeffect *effect) { ALuint id = effect->id - 1; ALsizei lidx = id >> 6; ALsizei slidx = id & 0x3f; memset(effect, 0, sizeof(*effect)); VECTOR_ELEM(device->EffectList, lidx).FreeMask |= U64(1) << slidx; }
static void FreeFilter(ALCdevice *device, ALfilter *filter) { ALuint id = filter->id - 1; ALsizei lidx = id >> 6; ALsizei slidx = id & 0x3f; memset(filter, 0, sizeof(*filter)); VECTOR_ELEM(device->FilterList, lidx).FreeMask |= U64(1) << slidx; }
void close_tsb(int lineno) { if(Open_tsb_index == NO_OPEN_TSB) { gf_error(M_GOLDFINGERPARSE, FLINE_f "Cannot close TSB since none is open!\n", GF_FLINE_NUM(lineno)); } sanity_check_tsb(VECTOR_ELEM(Tsb_vector, Open_tsb_index, tsb_vector_el_t)); Open_tsb_index = NO_OPEN_TSB; }
static inline ALeffect *LookupEffect(ALCdevice *device, ALuint id) { EffectSubList *sublist; ALuint lidx = (id-1) >> 6; ALsizei slidx = (id-1) & 0x3f; if(UNLIKELY(lidx >= VECTOR_SIZE(device->EffectList))) return NULL; sublist = &VECTOR_ELEM(device->EffectList, lidx); if(UNLIKELY(sublist->FreeMask & (U64(1)<<slidx))) return NULL; return sublist->Effects + slidx; }
static tsb_link_entry_t * start_new_chain(tsb_link_t *tsb_link, uint64_t tag, uint64_t data, block_t *block, block_tsb_t *block_tsb) { tsb_link_entry_t *entry; int new_index = add_vector_elements(&(tsb_link->entries), 1); entry = VECTOR_ELEM(tsb_link->entries, new_index, tsb_link_entry_vector_el_t); entry->tag = tag; entry->data = data; entry->link = EOL; entry->block = block; entry->block_tsb = block_tsb; entry->my_link = tsb_link->start_addr + (new_index * LINK_SIZE); entry->next = NULL; return entry; }
AL_API ALvoid AL_APIENTRY alDeleteAuxiliaryEffectSlots(ALsizei n, const ALuint *effectslots) { ALCcontext *context; ALeffectslot *slot; ALsizei i; context = GetContextRef(); if(!context) return; LockEffectSlotList(context); if(n < 0) SETERR_GOTO(context, AL_INVALID_VALUE, done, "Deleting %d effect slots", n); if(n == 0) goto done; for(i = 0;i < n;i++) { if((slot=LookupEffectSlot(context, effectslots[i])) == NULL) SETERR_GOTO(context, AL_INVALID_NAME, done, "Invalid effect slot ID %u", effectslots[i]); if(ReadRef(&slot->ref) != 0) SETERR_GOTO(context, AL_INVALID_NAME, done, "Deleting in-use effect slot %u", effectslots[i]); } // All effectslots are valid RemoveActiveEffectSlots(effectslots, n, context); for(i = 0;i < n;i++) { if((slot=LookupEffectSlot(context, effectslots[i])) == NULL) continue; VECTOR_ELEM(context->EffectSlotList, effectslots[i]-1) = NULL; DeinitEffectSlot(slot); memset(slot, 0, sizeof(*slot)); al_free(slot); } done: UnlockEffectSlotList(context); ALCcontext_DecRef(context); }
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; }
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; }
void ReadALConfig(void) { al_string confpaths = AL_STRING_INIT_STATIC(); al_string fname = AL_STRING_INIT_STATIC(); const char *str; FILE *f; str = "/etc/openal/alsoft.conf"; TRACE("Loading config %s...\n", str); f = al_fopen(str, "r"); if(f) { LoadConfigFromFile(f); fclose(f); } if(!(str=getenv("XDG_CONFIG_DIRS")) || str[0] == 0) str = "/etc/xdg"; alstr_copy_cstr(&confpaths, str); /* Go through the list in reverse, since "the order of base directories * denotes their importance; the first directory listed is the most * important". Ergo, we need to load the settings from the later dirs * first so that the settings in the earlier dirs override them. */ while(!alstr_empty(confpaths)) { char *next = strrchr(alstr_get_cstr(confpaths), ':'); if(next) { size_t len = next - alstr_get_cstr(confpaths); alstr_copy_cstr(&fname, next+1); VECTOR_RESIZE(confpaths, len, len+1); VECTOR_ELEM(confpaths, len) = 0; } else { alstr_reset(&fname); fname = confpaths; AL_STRING_INIT(confpaths); } if(alstr_empty(fname) || VECTOR_FRONT(fname) != '/') WARN("Ignoring XDG config dir: %s\n", alstr_get_cstr(fname)); else { if(VECTOR_BACK(fname) != '/') alstr_append_cstr(&fname, "/alsoft.conf"); else alstr_append_cstr(&fname, "alsoft.conf"); TRACE("Loading config %s...\n", alstr_get_cstr(fname)); f = al_fopen(alstr_get_cstr(fname), "r"); if(f) { LoadConfigFromFile(f); fclose(f); } } alstr_clear(&fname); } if((str=getenv("HOME")) != NULL && *str) { alstr_copy_cstr(&fname, str); if(VECTOR_BACK(fname) != '/') alstr_append_cstr(&fname, "/.alsoftrc"); else alstr_append_cstr(&fname, ".alsoftrc"); TRACE("Loading config %s...\n", alstr_get_cstr(fname)); f = al_fopen(alstr_get_cstr(fname), "r"); if(f) { LoadConfigFromFile(f); fclose(f); } } if((str=getenv("XDG_CONFIG_HOME")) != NULL && str[0] != 0) { alstr_copy_cstr(&fname, str); if(VECTOR_BACK(fname) != '/') alstr_append_cstr(&fname, "/alsoft.conf"); else alstr_append_cstr(&fname, "alsoft.conf"); } else { alstr_clear(&fname); if((str=getenv("HOME")) != NULL && str[0] != 0) { alstr_copy_cstr(&fname, str); if(VECTOR_BACK(fname) != '/') alstr_append_cstr(&fname, "/.config/alsoft.conf"); else alstr_append_cstr(&fname, ".config/alsoft.conf"); } } if(!alstr_empty(fname)) { TRACE("Loading config %s...\n", alstr_get_cstr(fname)); f = al_fopen(alstr_get_cstr(fname), "r"); if(f) { LoadConfigFromFile(f); fclose(f); } } alstr_clear(&fname); GetProcBinary(&fname, NULL); if(!alstr_empty(fname)) { if(VECTOR_BACK(fname) != '/') alstr_append_cstr(&fname, "/alsoft.conf"); else alstr_append_cstr(&fname, "alsoft.conf"); TRACE("Loading config %s...\n", alstr_get_cstr(fname)); f = al_fopen(alstr_get_cstr(fname), "r"); if(f) { LoadConfigFromFile(f); fclose(f); } } if((str=getenv("ALSOFT_CONF")) != NULL && *str) { TRACE("Loading config %s...\n", str); f = al_fopen(str, "r"); if(f) { LoadConfigFromFile(f); fclose(f); } } alstr_reset(&fname); alstr_reset(&confpaths); }
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); }
static ALCenum ALCwinmmCapture_open(ALCwinmmCapture *self, const ALCchar *name) { ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice; const al_string *iter; ALbyte *BufferData = NULL; DWORD CapturedDataSize; ALint BufferSize; UINT DeviceID; MMRESULT res; ALuint i; if(VECTOR_SIZE(CaptureDevices) == 0) ProbeCaptureDevices(); // Find the Device ID matching the deviceName if valid #define MATCH_DEVNAME(iter) (!alstr_empty(*(iter)) && (!name || alstr_cmp_cstr(*iter, name) == 0)) VECTOR_FIND_IF(iter, const al_string, CaptureDevices, MATCH_DEVNAME); if(iter == VECTOR_END(CaptureDevices)) return ALC_INVALID_VALUE; #undef MATCH_DEVNAME DeviceID = (UINT)(iter - VECTOR_BEGIN(CaptureDevices)); switch(device->FmtChans) { case DevFmtMono: case DevFmtStereo: break; case DevFmtQuad: case DevFmtX51: case DevFmtX51Rear: case DevFmtX61: case DevFmtX71: case DevFmtAmbi3D: 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; } memset(&self->Format, 0, sizeof(WAVEFORMATEX)); self->Format.wFormatTag = ((device->FmtType == DevFmtFloat) ? WAVE_FORMAT_IEEE_FLOAT : WAVE_FORMAT_PCM); self->Format.nChannels = ChannelsFromDevFmt(device->FmtChans, device->AmbiOrder); self->Format.wBitsPerSample = BytesFromDevFmt(device->FmtType) * 8; self->Format.nBlockAlign = self->Format.wBitsPerSample * self->Format.nChannels / 8; self->Format.nSamplesPerSec = device->Frequency; self->Format.nAvgBytesPerSec = self->Format.nSamplesPerSec * self->Format.nBlockAlign; self->Format.cbSize = 0; if((res=waveInOpen(&self->InHdl, DeviceID, &self->Format, (DWORD_PTR)&ALCwinmmCapture_waveInProc, (DWORD_PTR)self, 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 < (self->Format.nSamplesPerSec / 10)) CapturedDataSize = self->Format.nSamplesPerSec / 10; self->Ring = ll_ringbuffer_create(CapturedDataSize, self->Format.nBlockAlign, false); if(!self->Ring) goto failure; InitRef(&self->WaveBuffersCommitted, 0); // Create 4 Buffers of 50ms each BufferSize = self->Format.nAvgBytesPerSec / 20; BufferSize -= (BufferSize % self->Format.nBlockAlign); BufferData = calloc(4, BufferSize); if(!BufferData) goto failure; for(i = 0;i < 4;i++) { memset(&self->WaveBuffer[i], 0, sizeof(WAVEHDR)); self->WaveBuffer[i].dwBufferLength = BufferSize; self->WaveBuffer[i].lpData = ((i==0) ? (CHAR*)BufferData : (self->WaveBuffer[i-1].lpData + self->WaveBuffer[i-1].dwBufferLength)); self->WaveBuffer[i].dwFlags = 0; self->WaveBuffer[i].dwLoops = 0; waveInPrepareHeader(self->InHdl, &self->WaveBuffer[i], sizeof(WAVEHDR)); waveInAddBuffer(self->InHdl, &self->WaveBuffer[i], sizeof(WAVEHDR)); IncrementRef(&self->WaveBuffersCommitted); } ATOMIC_STORE(&self->killNow, AL_FALSE, almemory_order_release); if(althrd_create(&self->thread, ALCwinmmCapture_captureProc, self) != althrd_success) goto failure; alstr_copy(&device->DeviceName, VECTOR_ELEM(CaptureDevices, DeviceID)); return ALC_NO_ERROR; failure: if(BufferData) { for(i = 0;i < 4;i++) waveInUnprepareHeader(self->InHdl, &self->WaveBuffer[i], sizeof(WAVEHDR)); free(BufferData); } ll_ringbuffer_free(self->Ring); self->Ring = NULL; if(self->InHdl) waveInClose(self->InHdl); self->InHdl = NULL; return ALC_INVALID_VALUE; }
static ALCenum ALCwinmmPlayback_open(ALCwinmmPlayback *self, const ALCchar *deviceName) { ALCdevice *device = STATIC_CAST(ALCbackend, self)->mDevice; const al_string *iter; UINT DeviceID; MMRESULT res; if(VECTOR_SIZE(PlaybackDevices) == 0) ProbePlaybackDevices(); // Find the Device ID matching the deviceName if valid #define MATCH_DEVNAME(iter) (!alstr_empty(*(iter)) && \ (!deviceName || alstr_cmp_cstr(*(iter), deviceName) == 0)) VECTOR_FIND_IF(iter, const al_string, PlaybackDevices, MATCH_DEVNAME); if(iter == VECTOR_END(PlaybackDevices)) return ALC_INVALID_VALUE; #undef MATCH_DEVNAME DeviceID = (UINT)(iter - VECTOR_BEGIN(PlaybackDevices)); retry_open: memset(&self->Format, 0, sizeof(WAVEFORMATEX)); if(device->FmtType == DevFmtFloat) { self->Format.wFormatTag = WAVE_FORMAT_IEEE_FLOAT; self->Format.wBitsPerSample = 32; } else { self->Format.wFormatTag = WAVE_FORMAT_PCM; if(device->FmtType == DevFmtUByte || device->FmtType == DevFmtByte) self->Format.wBitsPerSample = 8; else self->Format.wBitsPerSample = 16; } self->Format.nChannels = ((device->FmtChans == DevFmtMono) ? 1 : 2); self->Format.nBlockAlign = self->Format.wBitsPerSample * self->Format.nChannels / 8; self->Format.nSamplesPerSec = device->Frequency; self->Format.nAvgBytesPerSec = self->Format.nSamplesPerSec * self->Format.nBlockAlign; self->Format.cbSize = 0; if((res=waveOutOpen(&self->OutHdl, DeviceID, &self->Format, (DWORD_PTR)&ALCwinmmPlayback_waveOutProc, (DWORD_PTR)self, CALLBACK_FUNCTION)) != MMSYSERR_NOERROR) { if(device->FmtType == DevFmtFloat) { device->FmtType = DevFmtShort; goto retry_open; } ERR("waveOutOpen failed: %u\n", res); goto failure; } alstr_copy(&device->DeviceName, VECTOR_ELEM(PlaybackDevices, DeviceID)); return ALC_NO_ERROR; failure: if(self->OutHdl) waveOutClose(self->OutHdl); self->OutHdl = NULL; return ALC_INVALID_VALUE; }