1 /*
2 * MOC - music on console
3 *
4 * SNDIO sound driver for MOC by Alexander Polakov.
5 * Copyright (C) 2011 Alexander Polakov <polachok@gmail.com>
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
11 *
12 */
13
14 #ifdef HAVE_CONFIG_H
15 # include "config.h"
16 #endif
17
18 #ifdef HAVE_SNDIO_H
19 # include <sndio.h>
20 #endif
21
22 #include <assert.h>
23
24 #include "common.h"
25 #include "audio.h"
26 #include "log.h"
27
28 #define PCT_TO_SIO(pct) ((127 * (pct) + 50) / 100)
29 #define SIO_TO_PCT(vol) ((100 * (vol) + 64) / 127)
30
31 static struct sio_hdl *hdl = NULL;
32 static int curvol = 100;
33 static struct sound_params params = { 0, 0, 0 };
34
35 static void sndio_close ();
36
volume_cb(void * addr ATTR_UNUSED,unsigned vol)37 static void volume_cb (void *addr ATTR_UNUSED, unsigned vol)
38 {
39 curvol = SIO_TO_PCT(vol);
40 }
41
sndio_init(struct output_driver_caps * caps)42 static int sndio_init (struct output_driver_caps *caps)
43 {
44 assert (caps != NULL);
45
46 caps->formats = SFMT_S8 | SFMT_U8 | SFMT_U16 | SFMT_S16 | SFMT_NE;
47 caps->min_channels = 1;
48 caps->max_channels = 2;
49
50 return 1;
51 }
52
sndio_shutdown()53 static void sndio_shutdown ()
54 {
55 if (hdl)
56 sndio_close ();
57 }
58
59 /* Return 0 on failure. */
sndio_open(struct sound_params * sound_params)60 static int sndio_open (struct sound_params *sound_params)
61 {
62 struct sio_par par;
63
64 assert (hdl == NULL);
65
66 if ((hdl = sio_open (NULL, SIO_PLAY, 0)) == NULL)
67 return 0;
68
69 params = *sound_params;
70 sio_initpar (&par);
71 /* Add volume change callback. */
72 sio_onvol (hdl, volume_cb, NULL);
73 par.rate = sound_params->rate;
74 par.pchan = sound_params->channels;
75 par.bits = (((sound_params->fmt & SFMT_S8) ||
76 (sound_params->fmt & SFMT_U8)) ? 8 : 16);
77 par.le = SIO_LE_NATIVE;
78 par.sig = (((sound_params->fmt & SFMT_S16) ||
79 (sound_params->fmt & SFMT_S8)) ? 1 : 0);
80 par.round = par.rate / 8;
81 par.appbufsz = par.round * 2;
82 logit ("rate %d pchan %d bits %d sign %d",
83 par.rate, par.pchan, par.bits, par.sig);
84
85 if (!sio_setpar (hdl, &par) || !sio_getpar (hdl, &par)
86 || !sio_start (hdl)) {
87 logit ("Failed to set sndio parameters.");
88 sio_close (hdl);
89 hdl = NULL;
90 return 0;
91 }
92 sio_setvol (hdl, PCT_TO_SIO(curvol));
93
94 return 1;
95 }
96
97 /* Return the number of bytes played, or -1 on error. */
sndio_play(const char * buff,const size_t size)98 static int sndio_play (const char *buff, const size_t size)
99 {
100 int count;
101
102 assert (hdl != NULL);
103
104 count = (int) sio_write (hdl, buff, size);
105 if (!count && sio_eof (hdl))
106 return -1;
107
108 return count;
109 }
110
sndio_close()111 static void sndio_close ()
112 {
113 assert (hdl != NULL);
114
115 sio_stop (hdl);
116 sio_close (hdl);
117 hdl = NULL;
118 }
119
sndio_read_mixer()120 static int sndio_read_mixer ()
121 {
122 return curvol;
123 }
124
sndio_set_mixer(int vol)125 static void sndio_set_mixer (int vol)
126 {
127 if (hdl != NULL)
128 sio_setvol (hdl, PCT_TO_SIO (vol));
129 }
130
sndio_get_buff_fill()131 static int sndio_get_buff_fill ()
132 {
133 assert (hdl != NULL);
134
135 /* Since we cannot stop SNDIO playing the samples already in
136 * its buffer, there will never be anything left unheard. */
137
138 return 0;
139 }
140
sndio_reset()141 static int sndio_reset ()
142 {
143 assert (hdl != NULL);
144
145 /* SNDIO will continue to play the samples already in its buffer
146 * regardless of what we do, so there's nothing we can do. */
147
148 return 1;
149 }
150
sndio_get_rate()151 static int sndio_get_rate ()
152 {
153 assert (hdl != NULL);
154
155 return params.rate;
156 }
157
sndio_toggle_mixer_channel()158 static void sndio_toggle_mixer_channel ()
159 {
160 assert (hdl != NULL);
161 }
162
sndio_get_mixer_channel_name()163 static char *sndio_get_mixer_channel_name ()
164 {
165 return xstrdup ("moc");
166 }
167
sndio_funcs(struct hw_funcs * funcs)168 void sndio_funcs (struct hw_funcs *funcs)
169 {
170 funcs->init = sndio_init;
171 funcs->shutdown = sndio_shutdown;
172 funcs->open = sndio_open;
173 funcs->close = sndio_close;
174 funcs->play = sndio_play;
175 funcs->read_mixer = sndio_read_mixer;
176 funcs->set_mixer = sndio_set_mixer;
177 funcs->get_buff_fill = sndio_get_buff_fill;
178 funcs->reset = sndio_reset;
179 funcs->get_rate = sndio_get_rate;
180 funcs->toggle_mixer_channel = sndio_toggle_mixer_channel;
181 funcs->get_mixer_channel_name = sndio_get_mixer_channel_name;
182 }
183