summaryrefslogtreecommitdiff
path: root/src/sys/alsa/volume-alsa.c
diff options
context:
space:
mode:
authorVito Caputo <vcaputo@pengaru.com>2017-05-26 21:51:04 -0700
committerVito Caputo <vcaputo@pengaru.com>2017-05-26 22:48:09 -0700
commit78f8fce7f286fd0c71774e2567404ed51f24fef3 (patch)
treef3de4987f7a9fc1bc03331e97b65a851b041051a /src/sys/alsa/volume-alsa.c
*: initial commit of stripped schism stuff
Forking schism tracker's IT playback stuff into a little playback library for embedding in demos.
Diffstat (limited to 'src/sys/alsa/volume-alsa.c')
-rw-r--r--src/sys/alsa/volume-alsa.c237
1 files changed, 237 insertions, 0 deletions
diff --git a/src/sys/alsa/volume-alsa.c b/src/sys/alsa/volume-alsa.c
new file mode 100644
index 0000000..9f81374
--- /dev/null
+++ b/src/sys/alsa/volume-alsa.c
@@ -0,0 +1,237 @@
+/*
+ * Schism Tracker - a cross-platform Impulse Tracker clone
+ * copyright (c) 2003-2005 Storlek <storlek@rigelseven.com>
+ * copyright (c) 2005-2008 Mrs. Brisby <mrs.brisby@nimh.org>
+ * copyright (c) 2009 Storlek & Mrs. Brisby
+ * copyright (c) 2010-2012 Storlek
+ * URL: http://schismtracker.org/
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program 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 General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include "headers.h"
+
+#include "util.h"
+
+#ifdef USE_ALSA
+#include <alsa/asoundlib.h>
+#include <alsa/mixer.h>
+
+static const char *alsa_card_id = "default";
+
+/* --------------------------------------------------------------------- */
+#ifdef USE_DLTRICK_ALSA
+#include <alsa/mixer.h>
+
+/* see midi-alsa for details about how this works */
+#include <dlfcn.h>
+
+extern void *_dltrick_handle;
+
+/* don't try this at home... */
+#define _void_dltrick(a,b,c) static void (*_dltrick_ ## a)b = NULL; \
+void a b { if (!_dltrick_##a) _dltrick_##a = dlsym(_dltrick_handle, #a); \
+if (!_dltrick_##a) abort(); _dltrick_ ## a c; }
+
+#define _any_dltrick(r,a,b,c) static r (*_dltrick_ ## a)b = NULL; \
+r a b { if (!_dltrick_##a) _dltrick_##a = dlsym(_dltrick_handle, #a); \
+if (!_dltrick_##a) abort(); return _dltrick_ ## a c; }
+
+_any_dltrick(snd_mixer_elem_t*, snd_mixer_find_selem,
+(snd_mixer_t*e,const snd_mixer_selem_id_t*sid),(e,sid))
+
+_void_dltrick(snd_mixer_selem_id_set_index,
+(snd_mixer_selem_id_t*obj,unsigned int val),(obj,val))
+
+_void_dltrick(snd_mixer_selem_id_set_name,
+(snd_mixer_selem_id_t*obj,const char *val),(obj,val))
+
+_any_dltrick(int,snd_mixer_selem_set_playback_volume,
+(snd_mixer_elem_t*e,snd_mixer_selem_channel_id_t ch,long v),(e,ch,v))
+
+_any_dltrick(int,snd_mixer_selem_is_playback_mono,(snd_mixer_elem_t*e),(e))
+_any_dltrick(int,snd_mixer_selem_has_playback_channel,(snd_mixer_elem_t*e,snd_mixer_selem_channel_id_t c),(e,c))
+
+_any_dltrick(int,snd_ctl_card_info,(snd_ctl_t*c,snd_ctl_card_info_t*i),(c,i))
+_any_dltrick(size_t,snd_ctl_card_info_sizeof,(void),())
+_any_dltrick(size_t,snd_mixer_selem_id_sizeof,(void),())
+
+_any_dltrick(int,snd_mixer_close,(snd_mixer_t*mm),(mm))
+_any_dltrick(int,snd_mixer_selem_get_playback_volume,
+(snd_mixer_elem_t*e,snd_mixer_selem_channel_id_t ch,long*v),(e,ch,v))
+#if (SND_LIB_MAJOR == 1 && SND_LIB_MINOR == 0 && SND_LIB_SUBMINOR < 10) || (SND_LIB_MAJOR < 1)
+_void_dltrick(snd_mixer_selem_get_playback_volume_range,
+(snd_mixer_elem_t*e,long*m,long*v),(e,m,v))
+#else
+_any_dltrick(int,snd_mixer_selem_get_playback_volume_range,
+(snd_mixer_elem_t*e,long*m,long*v),(e,m,v))
+#endif
+_any_dltrick(int,snd_ctl_open,(snd_ctl_t**c,const char *name,int mode),(c,name,mode))
+_any_dltrick(int,snd_ctl_close,(snd_ctl_t*ctl),(ctl))
+_any_dltrick(int,snd_mixer_open,(snd_mixer_t**m,int mode),(m,mode))
+_any_dltrick(int,snd_mixer_attach,(snd_mixer_t*m,const char *name),(m,name))
+_any_dltrick(int,snd_mixer_selem_register,(snd_mixer_t*m,
+ struct snd_mixer_selem_regopt*opt, snd_mixer_class_t **cp),(m,opt,cp))
+_any_dltrick(int,snd_mixer_selem_is_active,(snd_mixer_elem_t*e),(e))
+_any_dltrick(int,snd_mixer_selem_has_playback_volume,(snd_mixer_elem_t*e),(e))
+_any_dltrick(int,snd_mixer_selem_has_capture_switch,(snd_mixer_elem_t*e),(e))
+_any_dltrick(int,snd_mixer_selem_has_capture_switch_joined,(snd_mixer_elem_t*e),(e))
+_any_dltrick(int,snd_mixer_selem_has_capture_switch_exclusive,(snd_mixer_elem_t*e),(e))
+
+_any_dltrick(int,snd_mixer_load,(snd_mixer_t*m),(m))
+_any_dltrick(snd_mixer_elem_t*,snd_mixer_first_elem,(snd_mixer_t*m),(m))
+_any_dltrick(snd_mixer_elem_t*,snd_mixer_elem_next,(snd_mixer_elem_t*m),(m))
+_any_dltrick(snd_mixer_elem_type_t,snd_mixer_elem_get_type,(const snd_mixer_elem_t *obj),(obj))
+#endif
+
+/* alsa is paranoid, so snd_mixer_selem_id_alloca does an assert(&sid), which
+ * of course will never fail, so gcc complains. this shuts that warning up. */
+#undef assert
+#define assert(x)
+
+/* this _could_ change */
+static int current_alsa_range = 255;
+
+
+static void _alsa_writeout(snd_mixer_elem_t *em,
+ snd_mixer_selem_channel_id_t d,
+ int use, int lim)
+{
+ if (use > lim) use = lim;
+ (void)snd_mixer_selem_set_playback_volume(em, d, (long)use);
+}
+static void _alsa_write(snd_mixer_elem_t *em, int *l, int *r, long min, long range)
+{
+ long al, ar;
+ long mr, md;
+
+ al = ((*l) * range / current_alsa_range) + min;
+ ar = ((*r) * range / current_alsa_range) + min;
+
+ mr = min+range;
+
+ if (snd_mixer_selem_is_playback_mono(em)) {
+ md = ((al) + (ar)) / 2;
+
+ _alsa_writeout(em, SND_MIXER_SCHN_MONO, md, mr);
+ } else {
+ _alsa_writeout(em, SND_MIXER_SCHN_FRONT_LEFT, al, mr);
+ _alsa_writeout(em, SND_MIXER_SCHN_FRONT_RIGHT, ar, mr);
+#if 0
+/* this was probably wrong */
+ _alsa_writeout(em, SND_MIXER_SCHN_FRONT_CENTER, md, mr);
+ _alsa_writeout(em, SND_MIXER_SCHN_REAR_LEFT, al, mr);
+ _alsa_writeout(em, SND_MIXER_SCHN_REAR_RIGHT, ar, mr);
+ _alsa_writeout(em, SND_MIXER_SCHN_WOOFER, md, mr);
+#endif
+ }
+}
+static void _alsa_readin(snd_mixer_elem_t *em, snd_mixer_selem_channel_id_t d,
+ int *aa, long min, long range)
+{
+ long v;
+ if (snd_mixer_selem_has_playback_channel(em, d)) {
+ snd_mixer_selem_get_playback_volume(em, d, &v);
+ v -= min;
+ v = (v * current_alsa_range) / range;
+ (*aa) = v;
+ }
+
+}
+static void _alsa_config(UNUSED snd_mixer_elem_t *em, UNUSED int *l, UNUSED int *r, UNUSED long min, long range)
+{
+ current_alsa_range = range;
+}
+
+static void _alsa_read(snd_mixer_elem_t *em, int *l, int *r, long min, long range)
+{
+ if (snd_mixer_selem_is_playback_mono(em)) {
+ _alsa_readin(em, SND_MIXER_SCHN_MONO, l, min, range);
+ _alsa_readin(em, SND_MIXER_SCHN_MONO, r, min, range);
+ } else {
+ _alsa_readin(em, SND_MIXER_SCHN_FRONT_LEFT, l, min, range);
+ _alsa_readin(em, SND_MIXER_SCHN_FRONT_RIGHT, r, min, range);
+#if 0
+/* this was probably wrong */
+ _alsa_readin(em, SND_MIXER_SCHN_REAR_LEFT, l, min, range);
+ _alsa_readin(em, SND_MIXER_SCHN_REAR_RIGHT, r, min, range);
+ _alsa_readin(em, SND_MIXER_SCHN_FRONT_CENTER, l, min, range);
+ _alsa_readin(em, SND_MIXER_SCHN_FRONT_CENTER, r, min, range);
+ _alsa_readin(em, SND_MIXER_SCHN_WOOFER, l, min, range);
+ _alsa_readin(em, SND_MIXER_SCHN_WOOFER, r, min, range);
+#endif
+ }
+}
+
+static void _alsa_doit(void (*busy)(snd_mixer_elem_t *em,
+ int *, int *, long, long), int *l, int *r)
+{
+ long ml, mr;
+ snd_mixer_selem_id_t *sid;
+ snd_mixer_elem_t *em;
+ snd_mixer_t *mix;
+
+ snd_mixer_selem_id_alloca(&sid);
+ snd_mixer_selem_id_set_index(sid, 0);
+ snd_mixer_selem_id_set_name(sid, "Master");
+
+ if (snd_mixer_open(&mix, 0) == 0) {
+ if (snd_mixer_attach(mix, alsa_card_id) < 0) {
+ snd_mixer_close(mix);
+ return;
+ }
+ if (snd_mixer_selem_register(mix, NULL, NULL) < 0) {
+ snd_mixer_close(mix);
+ return;
+ }
+ if (snd_mixer_load(mix) < 0) {
+ snd_mixer_close(mix);
+ return;
+ }
+ em = snd_mixer_find_selem(mix, sid);
+ if (em) {
+ ml = mr = 0;
+ snd_mixer_selem_get_playback_volume_range(em, &ml, &mr);
+ if (ml != mr) {
+ busy(em, l, r, ml, mr - ml);
+ }
+ }
+ snd_mixer_close(mix);
+ }
+
+}
+
+
+int alsa_volume_get_max(void);
+int alsa_volume_get_max(void)
+{
+ int a1, a2;
+ _alsa_doit(_alsa_config, &a1, &a2);
+ return current_alsa_range;
+}
+
+void alsa_volume_read(int *left, int *right);
+void alsa_volume_read(int *left, int *right)
+{
+ *left = *right = 0;
+ _alsa_doit(_alsa_read, left, right);
+}
+
+void alsa_volume_write(int left, int right);
+void alsa_volume_write(int left, int right)
+{
+ _alsa_doit(_alsa_write, &left, &right);
+}
+#endif
© All Rights Reserved