From 4f6b15ea26b5fa09f300f67e4ce1057c2b39a3aa Mon Sep 17 00:00:00 2001 From: Bent Bisballe Nyeng Date: Thu, 25 Sep 2014 17:08:44 +0200 Subject: New API, new name, new version. --- src/mixer.cc | 321 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 321 insertions(+) create mode 100644 src/mixer.cc (limited to 'src/mixer.cc') diff --git a/src/mixer.cc b/src/mixer.cc new file mode 100644 index 0000000..5a6efb7 --- /dev/null +++ b/src/mixer.cc @@ -0,0 +1,321 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/* vim: set et sw=2 ts=2: */ +/*************************************************************************** + * mixer.cc + * + * Tue Sep 23 14:38:54 CEST 2014 + * Copyright 2014 Bent Bisballe Nyeng + * deva@aasimon.org + ****************************************************************************/ + +/* + * This file is part of LibAudioIO. + * + * LibAudioIO is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * LibAudioIO 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 + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with LibAudioIO; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ +#include "mixer.h" + +#include +#include + +#define fERROR (strtof("-INF", NULL)) + +Mixer::Mixer(snd_mixer_t *handle, snd_mixer_elem_t *elem) +{ + this->handle = handle; + this->elem = elem; + + /* + if (snd_mixer_selem_has_capture_volume(elem) || + snd_mixer_selem_has_capture_switch(elem)) { + printf("Capture channels:\n"); + if(snd_mixer_selem_is_capture_mono(elem)) { + printf(" Mono"); + } else { + for(int ichn = 0; ichn <= (int)SND_MIXER_SCHN_LAST; ichn++) { + snd_mixer_selem_channel_id_t chn = (snd_mixer_selem_channel_id_t)ichn; + if(!snd_mixer_selem_has_capture_channel(elem, chn)) continue; + printf(" - %s\n", snd_mixer_selem_channel_name(chn)); + } + } + } + */ + + + + + + + + /* + snd_mixer_selem_id_t *mixer; + + // Open mixer device + if(snd_mixer_open(&mixhnd, 0) != 0) + throw MixerInitilisationFailed(); + + if(snd_mixer_attach_hctl(mixhnd, hctl) != 0) + throw MixerInitilisationFailed(); + + if(snd_mixer_selem_register(mixhnd, NULL, NULL) < 0) + throw MixerInitilisationFailed(); + + if(snd_mixer_load(mixhnd) < 0) + throw MixerInitilisationFailed(); + + // Obtain mixer element + snd_mixer_selem_id_alloca(&mixer); + if(mixer == NULL) throw MixerInitilisationFailed(); + snd_mixer_selem_id_set_name(mixer, mixer_interface); + + elem = snd_mixer_find_selem(mixhnd, mixer); + if(elem == NULL) throw MixerInitilisationFailed(); + */ + + /* + // Obtain mixer enumeration element "Input Source" and set it to 2 (line). + snd_mixer_selem_id_set_name(mixer, "Input Source"); + + snd_mixer_elem_t *iselem = snd_mixer_find_selem(mixhnd, mixer); + if(iselem == NULL) return; + + if(snd_mixer_selem_is_enumerated(iselem)) { + // Set to line-in + for(int i = 0; i < 3; i++) { + char name[16]; + snd_mixer_selem_get_enum_item_name(iselem, i, sizeof(name), name); + if(std::string(name) == "Line") { + snd_mixer_selem_set_enum_item(iselem, SND_MIXER_SCHN_MONO, i); + } + } + } + */ +} + +Mixer::~Mixer() +{ + if(handle) snd_mixer_close(handle); +} + +snd_mixer_selem_channel_id_t Mixer::chanId(int idx) +{ + int num = 0; + if(snd_mixer_selem_is_capture_mono(elem)) { + if(idx == 0) return SND_MIXER_SCHN_MONO; + } else { + for(int ichn = 0; ichn <= (int)SND_MIXER_SCHN_LAST; ichn++) { + snd_mixer_selem_channel_id_t chn = (snd_mixer_selem_channel_id_t)ichn; + if(!snd_mixer_selem_has_capture_channel(elem, chn) && + !snd_mixer_selem_has_playback_channel(elem, chn)) continue; + if(idx == num) return chn; + num++; + } + } + return SND_MIXER_SCHN_UNKNOWN; +} + +int Mixer::numberOfChannels() +{ + int num = 0; + if(snd_mixer_selem_is_capture_mono(elem)) { + num = 1; + } else { + for(int ichn = 0; ichn <= (int)SND_MIXER_SCHN_LAST; ichn++) { + snd_mixer_selem_channel_id_t chn = (snd_mixer_selem_channel_id_t)ichn; + if(!snd_mixer_selem_has_capture_channel(elem, chn)) continue; + num++; + } + } + + return num; +} + +bool Mixer::isCapture() +{ + return snd_mixer_selem_has_capture_volume(elem) || + snd_mixer_selem_has_capture_switch(elem); +} + +bool Mixer::isPlayback() +{ + return snd_mixer_selem_has_playback_volume(elem); +} + +bool Mixer::isEnum() +{ + return snd_mixer_selem_is_enumerated(elem); +} + +void Mixer::setEnumValue(std::string value) +{ + if(!isEnum()) return; +} + +std::string Mixer::enumValue() +{ + if(!isEnum()) return ""; + + int i; + unsigned int idx; + char itemname[40]; + for(i = 0; !snd_mixer_selem_get_enum_item(elem, + (snd_mixer_selem_channel_id_t)i, + &idx); i++) { + snd_mixer_selem_get_enum_item_name(elem, idx, + sizeof(itemname) - 1, itemname); + return itemname; + } + + return ""; +} + +std::vector Mixer::enumValues() +{ + std::vector values; + if(!isEnum()) return values; + + int i, items; + char itemname[40]; + items = snd_mixer_selem_get_enum_items(elem); + for (i = 0; i < items; i++) { + snd_mixer_selem_get_enum_item_name(elem, (snd_mixer_selem_channel_id_t)i, + sizeof(itemname) - 1, itemname); + values.push_back(itemname); + } + + return values; +} + +int Mixer::setLevel(int channel, float level) +{ + int err; + long int value = level * 100; + // dir: -1 := exact or first below + // 0 := exact (error if not?) + // 1 := exact or first above + int dir = 1; + + if(isCapture()) { + err = snd_mixer_selem_set_capture_dB(elem, chanId(channel), value, dir); + if(err) { + printf("snd_mixer_selem_set_capture_dB: %s, %d\n", + snd_strerror(err), err); + return 1; + } + } + + if(isPlayback()) { + err = snd_mixer_selem_set_playback_dB(elem, chanId(channel), value, dir); + if(err) { + printf("snd_mixer_selem_set_playback_dB: %s, %d\n", + snd_strerror(err), err); + return 1; + } + } + + return 0; +} + +float Mixer::level(int channel) +{ + int err; + long int value; + + if(isCapture()) { + err = snd_mixer_selem_get_capture_dB(elem, chanId(channel), &value); + if(err) { + printf("snd_mixer_selem_get_capture_dB: %s, %d\n", + snd_strerror(err), err); + return fERROR; + } + } else if(isPlayback()) { + err = snd_mixer_selem_get_playback_dB(elem, chanId(channel), &value); + if(err) { + printf("snd_mixer_selem_get_playback_dB: %s, %d\n", + snd_strerror(err), err); + return fERROR; + } + } else { + return fERROR; + } + + return (float)value / 100.0; +} + +Mixer::range_t Mixer::range() +{ + Mixer::range_t range; + + int err; + long int lvl_min, lvl_max; + + if(isCapture()) { + err = snd_mixer_selem_get_capture_dB_range(elem, &lvl_min, &lvl_max); + + if(err) { + printf("snd_mixer_selem_get_capture_dB_range: %s, %d\n", + snd_strerror(err), err); + } + } else if(isPlayback()) { + err = snd_mixer_selem_get_playback_dB_range(elem, &lvl_min, &lvl_max); + + if(err) { + printf("snd_mixer_selem_get_playback_dB_range: %s, %d\n", + snd_strerror(err), err); + } + } else { + range.min = fERROR; + range.max = fERROR; + return range; + } + + range.min = (float)lvl_min / 100.0; + range.max = (float)lvl_max / 100.0; + + return range; +} + +void Mixer::setCapture(bool capture) +{ + if(!isCapture()) return; + int c = capture?1:0; + int err; + err = snd_mixer_selem_set_capture_switch_all(elem, c); + if(err) { + printf("snd_mixer_selem_set_capture_switch_all: %s, %d\n", + snd_strerror(err), err); + } +} + +bool Mixer::capture() +{ + if(!isCapture()) return false; + + int err; + + int num = numberOfChannels(); + for(int idx = 0; idx < num; idx++) { + int value; + err = snd_mixer_selem_get_capture_switch(elem, chanId(idx), &value); + if(err) { + printf(" snd_mixer_selem_get_capture_switch: %s, %d\n", + snd_strerror(err), err); + return false; + } + if(value == 0) return false; + } + + return true; +} -- cgit v1.2.3