summaryrefslogtreecommitdiff
path: root/shell/audio/sdl/sound_output.c
blob: 075871839f0979ac5bd8f5231c449f9671e1d4b0 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
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;
}