summaryrefslogtreecommitdiff
path: root/shell/audio
diff options
context:
space:
mode:
Diffstat (limited to 'shell/audio')
-rw-r--r--shell/audio/alsa/sound_output.c146
-rw-r--r--shell/audio/oss/sound_output.c63
-rw-r--r--shell/audio/portaudio/sound_output.c45
-rw-r--r--shell/audio/sdl/sound_output.c119
-rw-r--r--shell/audio/sound_output.h12
5 files changed, 385 insertions, 0 deletions
diff --git a/shell/audio/alsa/sound_output.c b/shell/audio/alsa/sound_output.c
new file mode 100644
index 0000000..4da70a7
--- /dev/null
+++ b/shell/audio/alsa/sound_output.c
@@ -0,0 +1,146 @@
+#include <sys/ioctl.h>
+#include <stdint.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <alsa/asoundlib.h>
+
+#include "sound_output.h"
+
+static snd_pcm_t *handle;
+
+uint32_t Audio_Init()
+{
+ snd_pcm_hw_params_t *params;
+ uint32_t val;
+ int32_t dir = -1;
+ snd_pcm_uframes_t frames;
+
+ /* Open PCM device for playback. */
+ int32_t rc = snd_pcm_open(&handle, "default", SND_PCM_STREAM_PLAYBACK, 0);
+
+ if (rc < 0)
+ rc = snd_pcm_open(&handle, "plughw:0,0,0", SND_PCM_STREAM_PLAYBACK, 0);
+
+ if (rc < 0)
+ rc = snd_pcm_open(&handle, "plughw:0,0", SND_PCM_STREAM_PLAYBACK, 0);
+
+ if (rc < 0)
+ rc = snd_pcm_open(&handle, "plughw:1,0,0", SND_PCM_STREAM_PLAYBACK, 0);
+
+ if (rc < 0)
+ rc = snd_pcm_open(&handle, "plughw:1,0", SND_PCM_STREAM_PLAYBACK, 0);
+
+ if (rc < 0)
+ {
+ fprintf(stderr, "unable to open PCM device: %s\n", snd_strerror(rc));
+ return 1;
+ }
+
+ /* Allocate a hardware parameters object. */
+ snd_pcm_hw_params_alloca(&params);
+
+ /* Fill it in with default values. */
+ rc = snd_pcm_hw_params_any(handle, params);
+ if (rc < 0)
+ {
+ fprintf(stderr, "Error:snd_pcm_hw_params_any %s\n", snd_strerror(rc));
+ return 1;
+ }
+
+ /* Set the desired hardware parameters. */
+
+ /* Interleaved mode */
+ rc = snd_pcm_hw_params_set_access(handle, params, SND_PCM_ACCESS_RW_INTERLEAVED);
+ if (rc < 0)
+ {
+ fprintf(stderr, "Error:snd_pcm_hw_params_set_access %s\n", snd_strerror(rc));
+ return 1;
+ }
+
+ /* Signed 16-bit little-endian format */
+ rc = snd_pcm_hw_params_set_format(handle, params, SND_PCM_FORMAT_S16_LE);
+ if (rc < 0)
+ {
+ fprintf(stderr, "Error:snd_pcm_hw_params_set_format %s\n", snd_strerror(rc));
+ return 1;
+ }
+
+ /* Two channels (stereo) */
+ rc = snd_pcm_hw_params_set_channels(handle, params, 2);
+ if (rc < 0)
+ {
+ fprintf(stderr, "Error:snd_pcm_hw_params_set_channels %s\n", snd_strerror(rc));
+ return 1;
+ }
+
+ val = SOUND_OUTPUT_FREQUENCY;
+ rc = snd_pcm_hw_params_set_rate_near(handle, params, &val, &dir);
+ if (rc < 0)
+ {
+ fprintf(stderr, "Error:snd_pcm_hw_params_set_rate_near %s\n", snd_strerror(rc));
+ return 1;
+ }
+
+ /* Set period size to settings.aica.BufferSize frames. */
+ frames = SOUND_SAMPLES_SIZE;
+ rc = snd_pcm_hw_params_set_period_size_near(handle, params, &frames, &dir);
+ if (rc < 0)
+ {
+ fprintf(stderr, "Error:snd_pcm_hw_params_set_buffer_size_near %s\n", snd_strerror(rc));
+ return 1;
+ }
+ frames *= 4;
+ rc = snd_pcm_hw_params_set_buffer_size_near(handle, params, &frames);
+ if (rc < 0)
+ {
+ fprintf(stderr, "Error:snd_pcm_hw_params_set_buffer_size_near %s\n", snd_strerror(rc));
+ return 1;
+ }
+
+ /* Write the parameters to the driver */
+ rc = snd_pcm_hw_params(handle, params);
+ if (rc < 0)
+ {
+ fprintf(stderr, "Unable to set hw parameters: %s\n", snd_strerror(rc));
+ return 1;
+ }
+
+ return 0;
+}
+
+void Audio_Write(int16_t* restrict buffer, uint32_t buffer_size)
+{
+ uint32_t i;
+ long ret, len;
+
+ if (!handle) return;
+
+ len = buffer_size;
+
+ ret = snd_pcm_writei(handle, buffer, len);
+ while(ret != len)
+ {
+ if (ret < 0)
+ {
+ snd_pcm_prepare( handle );
+ }
+ else
+ {
+ len -= ret;
+ }
+ ret = snd_pcm_writei(handle, buffer, len);
+ }
+}
+
+bool Audio_Underrun_Likely() {
+ return false;
+}
+
+void Audio_Close()
+{
+ if (handle)
+ {
+ snd_pcm_drain(handle);
+ snd_pcm_close(handle);
+ }
+}
diff --git a/shell/audio/oss/sound_output.c b/shell/audio/oss/sound_output.c
new file mode 100644
index 0000000..39a7ba3
--- /dev/null
+++ b/shell/audio/oss/sound_output.c
@@ -0,0 +1,63 @@
+#include <stdio.h>
+#include <sys/ioctl.h>
+#include <stdint.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <sys/soundcard.h>
+
+#include "sound_output.h"
+
+static int32_t oss_audio_fd = -1;
+
+uint32_t Audio_Init()
+{
+ uint32_t channels = 2;
+ uint32_t format = AFMT_S16_LE;
+ uint32_t tmp = SOUND_OUTPUT_FREQUENCY;
+ int32_t err_ret;
+
+ oss_audio_fd = open("/dev/dsp", O_WRONLY | O_NONBLOCK);
+ if (oss_audio_fd < 0)
+ {
+ printf("Couldn't open /dev/dsp.\n");
+ return 1;
+ }
+
+ err_ret = ioctl(oss_audio_fd, SNDCTL_DSP_SPEED,&tmp);
+ if (err_ret == -1)
+ {
+ printf("Could not set sound frequency\n");
+ return 1;
+ }
+ err_ret = ioctl(oss_audio_fd, SNDCTL_DSP_CHANNELS, &channels);
+ if (err_ret == -1)
+ {
+ printf("Could not set channels\n");
+ return 1;
+ }
+ err_ret = ioctl(oss_audio_fd, SNDCTL_DSP_SETFMT, &format);
+ if (err_ret == -1)
+ {
+ printf("Could not set sound format\n");
+ return 1;
+ }
+ return 0;
+}
+
+void Audio_Write(int16_t* restrict buffer, uint32_t buffer_size)
+{
+ write(oss_audio_fd, buffer, buffer_size * 4 );
+}
+
+bool Audio_Underrun_Likely() {
+ return false;
+}
+
+void Audio_Close()
+{
+ if (oss_audio_fd >= 0)
+ {
+ close(oss_audio_fd);
+ oss_audio_fd = -1;
+ }
+}
diff --git a/shell/audio/portaudio/sound_output.c b/shell/audio/portaudio/sound_output.c
new file mode 100644
index 0000000..0c03c93
--- /dev/null
+++ b/shell/audio/portaudio/sound_output.c
@@ -0,0 +1,45 @@
+#include <portaudio.h>
+#include <stdint.h>
+#include <stdio.h>
+
+#include "shared.h"
+
+static PaStream *apu_stream;
+
+uint32_t Audio_Init()
+{
+ Pa_Initialize();
+
+ PaStreamParameters outputParameters;
+
+ outputParameters.device = Pa_GetDefaultOutputDevice();
+
+ if (outputParameters.device == paNoDevice)
+ {
+ printf("No sound output\n");
+ return 1;
+ }
+
+ outputParameters.channelCount = 2;
+ outputParameters.sampleFormat = paInt16;
+ outputParameters.hostApiSpecificStreamInfo = NULL;
+
+ Pa_OpenStream( &apu_stream, NULL, &outputParameters, SOUND_OUTPUT_FREQUENCY, SOUND_SAMPLES_SIZE, paNoFlag, NULL, NULL);
+ Pa_StartStream( apu_stream );
+
+ return 0;
+}
+
+void Audio_Write(int16_t* restrict buffer, uint32_t buffer_size)
+{
+ Pa_WriteStream( apu_stream, buffer, buffer_size);
+}
+
+bool Audio_Underrun_Likely() {
+ return false;
+}
+
+void Audio_Close()
+{
+ //Pa_Close();
+}
diff --git a/shell/audio/sdl/sound_output.c b/shell/audio/sdl/sound_output.c
new file mode 100644
index 0000000..0758718
--- /dev/null
+++ b/shell/audio/sdl/sound_output.c
@@ -0,0 +1,119 @@
+#include <sys/ioctl.h>
+#include <stdint.h>
+#include <stdbool.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <SDL/SDL.h>
+
+#include "sound_output.h"
+
+#define UNDERRUN_THRESHOLD 0.5
+
+static int32_t BUFFSIZE;
+static uint8_t *buffer;
+static uint32_t buf_read_pos = 0;
+static uint32_t buf_write_pos = 0;
+static int32_t buffered_bytes = 0;
+
+static int32_t sdl_read_buffer(uint8_t* data, int32_t len)
+{
+ if (buffered_bytes >= len)
+ {
+ if(buf_read_pos + len <= BUFFSIZE )
+ {
+ memcpy(data, buffer + buf_read_pos, len);
+ }
+ else
+ {
+ int32_t tail = BUFFSIZE - buf_read_pos;
+ memcpy(data, buffer + buf_read_pos, tail);
+ memcpy(data + tail, buffer, len - tail);
+ }
+ buf_read_pos = (buf_read_pos + len) % BUFFSIZE;
+ buffered_bytes -= len;
+ }
+
+ return len;
+}
+
+
+static void sdl_write_buffer(uint8_t* data, int32_t len)
+{
+ SDL_LockAudio();
+ for(uint32_t i = 0; i < len; i += 4)
+ {
+ while (buffered_bytes == BUFFSIZE) {
+ SDL_UnlockAudio();
+ usleep(1000);
+ SDL_LockAudio();
+ }
+ *(int32_t*)((char*)(buffer + buf_write_pos)) = *(int32_t*)((char*)(data + i));
+ //memcpy(buffer + buf_write_pos, data + i, 4);
+ buf_write_pos = (buf_write_pos + 4) % BUFFSIZE;
+ buffered_bytes += 4;
+ }
+ SDL_UnlockAudio();
+}
+
+void sdl_callback(void *unused, uint8_t *stream, int32_t len)
+{
+ sdl_read_buffer((uint8_t *)stream, len);
+}
+uint32_t Audio_Init()
+{
+ SDL_AudioSpec aspec, obtained;
+
+ BUFFSIZE = (SOUND_SAMPLES_SIZE * 2 * 2) * 4;
+ buffer = (uint8_t *) malloc(BUFFSIZE);
+
+ /* Add some silence to the buffer */
+ buffered_bytes = 0;
+ buf_read_pos = 0;
+ buf_write_pos = 0;
+
+ aspec.format = AUDIO_S16SYS;
+ aspec.freq = SOUND_OUTPUT_FREQUENCY;
+ aspec.channels = 2;
+ aspec.samples = SOUND_SAMPLES_SIZE;
+ aspec.callback = (sdl_callback);
+ aspec.userdata = NULL;
+
+ /* initialize the SDL Audio system */
+ if (SDL_InitSubSystem (SDL_INIT_AUDIO | SDL_INIT_NOPARACHUTE))
+ {
+ printf("SDL: Initializing of SDL Audio failed: %s.\n", SDL_GetError());
+ return 1;
+ }
+
+ /* Open the audio device and start playing sound! */
+ if(SDL_OpenAudio(&aspec, &obtained) < 0)
+ {
+ printf("SDL: Unable to open audio: %s\n", SDL_GetError());
+ return 1;
+ }
+
+ SDL_PauseAudio(0);
+
+ return 0;
+}
+
+void Audio_Write(int16_t* restrict buffer, uint32_t buffer_size)
+{
+ sdl_write_buffer(buffer, buffer_size * 4);
+}
+
+bool Audio_Underrun_Likely() {
+ bool underrun_likely = false;
+ SDL_LockAudio();
+ underrun_likely = buffered_bytes < BUFFSIZE * UNDERRUN_THRESHOLD;
+ SDL_UnlockAudio();
+ return underrun_likely;
+}
+
+void Audio_Close()
+{
+ SDL_PauseAudio(1);
+ SDL_CloseAudio();
+ SDL_QuitSubSystem(SDL_INIT_AUDIO);
+ buffer = NULL;
+}
diff --git a/shell/audio/sound_output.h b/shell/audio/sound_output.h
new file mode 100644
index 0000000..b770fbe
--- /dev/null
+++ b/shell/audio/sound_output.h
@@ -0,0 +1,12 @@
+#ifndef SOUND_OUTPUT_H
+#define SOUND_OUTPUT_H
+
+#include <stdbool.h>
+#include "shared.h"
+
+extern uint32_t Audio_Init();
+extern void Audio_Write(int16_t* restrict buffer, uint32_t buffer_size);
+extern bool Audio_Underrun_Likely();
+extern void Audio_Close();
+
+#endif