3 #include <alsa/asoundlib.h>
9 static snd_pcm_t *handle;
10 static snd_pcm_sframes_t frames;
11 static AudioSpec audioSpec { };
13 static Semaphore pauseSemaphore { };
15 static const char *device = "default";
17 static snd_mixer_t *mixer_handle;
19 static double volume, balance;
21 public void AudioSetBalance(double percent)
26 public bool AudioSetVolume(VolumeControl type, double percent)
29 if(type == application)
36 snd_mixer_elem_t *elem;
37 snd_mixer_selem_id_t *sid;
42 snd_mixer_load(mixer_handle);
44 // snd_mixer_selem_id_alloca(&sid);
45 sid = (snd_mixer_selem_id_t *) alloca(snd_mixer_selem_id_sizeof());
46 memset(sid, 0, snd_mixer_selem_id_sizeof());
48 snd_mixer_selem_id_set_index(sid, 0);
49 snd_mixer_selem_id_set_name(sid, (type == pcm) ? "PCM" : "Master");
50 elem = snd_mixer_find_selem(mixer_handle, sid);
53 snd_mixer_selem_get_playback_volume_range(elem,&pmin,&pmax);
54 f_multi = 1 / (float)(pmax - pmin);
55 set_vol = (int)(percent / f_multi + pmin + 0.5);
56 snd_mixer_selem_set_playback_volume(elem, 0, set_vol);
57 snd_mixer_selem_set_playback_volume(elem, 1, set_vol);
60 snd_mixer_free(mixer_handle);
65 public bool AudioGetVolume(VolumeControl type, double * percent)
68 if(type == application)
75 snd_mixer_elem_t *elem;
76 snd_mixer_selem_id_t *sid;
81 snd_mixer_load(mixer_handle);
83 // snd_mixer_selem_id_alloca(&sid);
84 sid = (snd_mixer_selem_id_t *) alloca(snd_mixer_selem_id_sizeof());
85 memset(sid, 0, snd_mixer_selem_id_sizeof());
87 snd_mixer_selem_id_set_index(sid, 0);
88 snd_mixer_selem_id_set_name(sid, (type == pcm) ? "PCM" : "Master");
89 elem = snd_mixer_find_selem(mixer_handle, sid);
93 snd_mixer_selem_get_playback_volume_range(elem,&pmin,&pmax);
94 snd_mixer_selem_get_playback_volume(elem, 0, &set_vol);
95 f_multi = 1 / (float)(pmax - pmin);
96 *percent = f_multi * (set_vol - 0.5 - pmin);
99 snd_mixer_free(mixer_handle);
104 public void OpenMixer()
106 snd_mixer_open(&mixer_handle, 0);
107 snd_mixer_attach(mixer_handle, "default");
108 snd_mixer_selem_register(mixer_handle, null, null);
111 public void CloseMixer()
113 snd_mixer_close(mixer_handle);
116 public int OpenAudio(AudioSpec wanted, AudioSpec result)
120 buffer = new byte[wanted.samples * wanted.channels * wanted.bits / 8];
121 memset(buffer, 0, wanted.samples * wanted.channels * wanted.bits / 8);
123 if ((err = snd_pcm_open(&handle, device, SND_PCM_STREAM_PLAYBACK, 0)) < 0)
125 printf("Playback open error: %s\n", snd_strerror(err));
128 if ((err = snd_pcm_set_params(handle,
129 (wanted.bits == 8) ? SND_PCM_FORMAT_U8 : SND_PCM_FORMAT_S16,
130 SND_PCM_ACCESS_RW_INTERLEAVED,
136 printf("Playback open error: %s\n", snd_strerror(err));
139 soundThread.done = false;
142 volume = wanted.volume;
147 public void PauseAudio(bool value)
151 soundThread.done = true;
155 soundThread.Create();
158 public void CloseAudio()
160 soundThread.done = true;
163 if(handle) snd_pcm_close(handle);
166 static class SoundThread : Thread
184 pauseSemaphore.Wait();
189 short int * samples = (short int *)buffer;
190 double m = volume / (1 + Abs(balance * 2 - 1)) / 100.0;
191 double ll = (2 - (2 * Max(balance, 0.5)))* m;
192 double lr = (-2 * Min(balance, 0.5) + 1) * m;
193 double rl = (2 * Max(balance, 0.5) - 1) * m;
194 double rr = (2 * Min(balance, 0.5)) * m;
195 uint numSamples = audioSpec.samples/16;
196 // printf("Volume: %f, m : %f, Left: (%f, %f), Right: (%f, %f) \n", volume, m, ll, lr, rl, rr);
198 audioSpec.callback(audioSpec.userdata, buffer, numSamples * audioSpec.channels * audioSpec.bits / 8);
199 for(c = 0; c<numSamples; c++)
201 short sLeft = samples[0], sRight = samples[1];
202 samples[0] = (short)(sLeft * ll + sRight * lr);
203 samples[1] = (short)(sLeft * rl + sRight * rr);
207 frames = snd_pcm_writei(handle, buffer, numSamples);
209 frames = snd_pcm_recover(handle, (int)frames, 0);
212 printf("snd_pcm_writei failed: %s\n", snd_strerror((int)frames));
215 if (frames > 0 && frames < numSamples)
216 printf("Short write (expected %ui, wrote %li)\n", numSamples, frames);
223 static SoundThread soundThread { };