119 lines
		
	
	
		
			2.6 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
		
		
			
		
	
	
			119 lines
		
	
	
		
			2.6 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
|  | #include <AL/al.h>
 | ||
|  | #include <AL/alc.h>
 | ||
|  | #include <assert.h>
 | ||
|  | #include <emscripten.h>
 | ||
|  | #include <kinc/audio2/audio.h>
 | ||
|  | #include <stdio.h>
 | ||
|  | #include <stdlib.h>
 | ||
|  | 
 | ||
|  | static kinc_a2_buffer_t a2_buffer; | ||
|  | 
 | ||
|  | static ALCdevice *device = NULL; | ||
|  | static ALCcontext *context = NULL; | ||
|  | static unsigned int channels = 0; | ||
|  | static unsigned int bits = 0; | ||
|  | static ALenum format = 0; | ||
|  | static ALuint source = 0; | ||
|  | 
 | ||
|  | static bool audioRunning = false; | ||
|  | #define BUFSIZE 4096
 | ||
|  | static short buf[BUFSIZE]; | ||
|  | #define NUM_BUFFERS 3
 | ||
|  | 
 | ||
|  | static uint32_t samples_per_second = 44100; | ||
|  | 
 | ||
|  | static void copySample(void *buffer) { | ||
|  | 	float left_value = *(float *)&a2_buffer.channels[0][a2_buffer.read_location]; | ||
|  | 	float right_value = *(float *)&a2_buffer.channels[1][a2_buffer.read_location]; | ||
|  | 	a2_buffer.read_location += 1; | ||
|  | 	if (a2_buffer.read_location >= a2_buffer.data_size) { | ||
|  | 		a2_buffer.read_location = 0; | ||
|  | 	} | ||
|  | 	((int16_t *)buffer)[0] = (int16_t)(left_value * 32767); | ||
|  | 	((int16_t *)buffer)[1] = (int16_t)(right_value * 32767); | ||
|  | } | ||
|  | 
 | ||
|  | static void streamBuffer(ALuint buffer) { | ||
|  | 	if (kinc_a2_internal_callback(&a2_buffer, BUFSIZE / 2)) { | ||
|  | 		for (int i = 0; i < BUFSIZE; i += 2) { | ||
|  | 			copySample(&buf[i]); | ||
|  | 		} | ||
|  | 	} | ||
|  | 
 | ||
|  | 	alBufferData(buffer, format, buf, BUFSIZE * 2, samples_per_second); | ||
|  | } | ||
|  | 
 | ||
|  | static void iter() { | ||
|  | 	if (!audioRunning) { | ||
|  | 		return; | ||
|  | 	} | ||
|  | 
 | ||
|  | 	ALint processed; | ||
|  | 	alGetSourcei(source, AL_BUFFERS_PROCESSED, &processed); | ||
|  | 
 | ||
|  | 	if (processed <= 0) { | ||
|  | 		return; | ||
|  | 	} | ||
|  | 	while (processed--) { | ||
|  | 		ALuint buffer; | ||
|  | 		alSourceUnqueueBuffers(source, 1, &buffer); | ||
|  | 		streamBuffer(buffer); | ||
|  | 		alSourceQueueBuffers(source, 1, &buffer); | ||
|  | 	} | ||
|  | 
 | ||
|  | 	ALint playing; | ||
|  | 	alGetSourcei(source, AL_SOURCE_STATE, &playing); | ||
|  | 	if (playing != AL_PLAYING) { | ||
|  | 		alSourcePlay(source); | ||
|  | 	} | ||
|  | } | ||
|  | 
 | ||
|  | static bool a2_initialized = false; | ||
|  | 
 | ||
|  | void kinc_a2_init() { | ||
|  | 	if (a2_initialized) { | ||
|  | 		return; | ||
|  | 	} | ||
|  | 
 | ||
|  | 	kinc_a2_internal_init(); | ||
|  | 	a2_initialized = true; | ||
|  | 
 | ||
|  | 	a2_buffer.read_location = 0; | ||
|  | 	a2_buffer.write_location = 0; | ||
|  | 	a2_buffer.data_size = 128 * 1024; | ||
|  | 	a2_buffer.channel_count = 2; | ||
|  | 	a2_buffer.channels[0] = (float*)malloc(a2_buffer.data_size * sizeof(float)); | ||
|  | 	a2_buffer.channels[1] = (float*)malloc(a2_buffer.data_size * sizeof(float)); | ||
|  | 
 | ||
|  | 	audioRunning = true; | ||
|  | 
 | ||
|  | 	device = alcOpenDevice(NULL); | ||
|  | 	context = alcCreateContext(device, NULL); | ||
|  | 	alcMakeContextCurrent(context); | ||
|  | 	format = AL_FORMAT_STEREO16; | ||
|  | 
 | ||
|  | 	ALuint buffers[NUM_BUFFERS]; | ||
|  | 	alGenBuffers(NUM_BUFFERS, buffers); | ||
|  | 	alGenSources(1, &source); | ||
|  | 
 | ||
|  | 	streamBuffer(buffers[0]); | ||
|  | 	streamBuffer(buffers[1]); | ||
|  | 	streamBuffer(buffers[2]); | ||
|  | 
 | ||
|  | 	alSourceQueueBuffers(source, NUM_BUFFERS, buffers); | ||
|  | 
 | ||
|  | 	alSourcePlay(source); | ||
|  | } | ||
|  | 
 | ||
|  | void kinc_a2_update() { | ||
|  | 	iter(); | ||
|  | } | ||
|  | 
 | ||
|  | void kinc_a2_shutdown() { | ||
|  | 	audioRunning = false; | ||
|  | } | ||
|  | 
 | ||
|  | uint32_t kinc_a2_samples_per_second(void) { | ||
|  | 	return samples_per_second; | ||
|  | } |