| @@ -23,7 +23,7 @@ LDLIBS_1 = -lSDL2 | |||||
| SRC_SRCS_1 = nese.c ines.c | SRC_SRCS_1 = nese.c ines.c | ||||
| SRC_SRCS_1 += nes.c ppu.c input.c | SRC_SRCS_1 += nes.c ppu.c input.c | ||||
| SRC_SRCS_1 += cart.c mapper.c | SRC_SRCS_1 += cart.c mapper.c | ||||
| SRC_SRCS_1 += apu.c | |||||
| SRC_SRCS_1 += apu.c audio.c | |||||
| SRC_SRCS_1 += sdl_render.c sdl_input.c sdl_audio.c | SRC_SRCS_1 += sdl_render.c sdl_input.c sdl_audio.c | ||||
| MAPDIR = src/map | MAPDIR = src/map | ||||
| @@ -0,0 +1 @@ | |||||
| ../blip-buf | |||||
| @@ -0,0 +1,17 @@ | |||||
| #include "audio.h" | |||||
| #include "blip-buf/blip_buf.h" | |||||
| int nes_audio_fill(nes_Audio_Stream* stream, nes_apu* apu) { | |||||
| int status = 0; | |||||
| blip_end_frame(apu->blip, apu->time); | |||||
| apu->time = 0; | |||||
| while (status == 0 && blip_samples_avail(apu->blip) > 0) { | |||||
| short samples[1024]; | |||||
| int n_samples = blip_read_samples( | |||||
| apu->blip, samples, 1024, 0 | |||||
| ); | |||||
| status = nes_audio_push(stream, samples, n_samples); | |||||
| } | |||||
| return status; | |||||
| } | |||||
| @@ -0,0 +1,37 @@ | |||||
| #ifndef NES_AUDIO_H_ | |||||
| #define NES_AUDIO_H_ | |||||
| #include "apu.h" | |||||
| // System Glue | |||||
| typedef struct nes_Audio_Stream_t { | |||||
| int (*init)(struct nes_Audio_Stream_t*, int frequency); | |||||
| void (*done)(struct nes_Audio_Stream_t*); | |||||
| int (*push)(struct nes_Audio_Stream_t*, short*, int); | |||||
| void* data; | |||||
| } nes_Audio_Stream; | |||||
| static inline int nes_audio_init(nes_Audio_Stream* stream, | |||||
| int frequency) { | |||||
| return stream->init(stream, frequency); | |||||
| } | |||||
| static inline void nes_audio_done(nes_Audio_Stream* stream) { | |||||
| stream->done(stream); | |||||
| } | |||||
| static inline int nes_audio_push(nes_Audio_Stream* stream, | |||||
| short* samples, int n_samples) { | |||||
| return stream->push(stream, samples, n_samples); | |||||
| } | |||||
| // Convenience | |||||
| int nes_audio_fill(nes_Audio_Stream* stream, nes_apu* apu); | |||||
| #endif // NES_AUDIO_H_ | |||||
| @@ -0,0 +1,60 @@ | |||||
| #include <SDL2/SDL.h> | |||||
| #include "audio.h" | |||||
| typedef struct { | |||||
| SDL_AudioDeviceID id; | |||||
| } sdl_audio_device; | |||||
| static sdl_audio_device the_audio_device = {0}; | |||||
| int sdl_audio_init(nes_Audio_Stream* stream, int frequency) { | |||||
| int status = SDL_Init(SDL_INIT_AUDIO); | |||||
| if (0 == status) { | |||||
| sdl_audio_device* device = &the_audio_device; | |||||
| SDL_AudioSpec as = { | |||||
| .freq = frequency, | |||||
| .format = AUDIO_S16SYS, | |||||
| .channels = 1, | |||||
| }; | |||||
| device->id = SDL_OpenAudioDevice(NULL, 0, &as, NULL, 0); | |||||
| if (0 == device->id) { | |||||
| printf("SDL: %s\n", SDL_GetError()); | |||||
| status = -1; | |||||
| } else { | |||||
| stream->data = device; | |||||
| SDL_PauseAudioDevice(device->id, 0); | |||||
| } | |||||
| } | |||||
| return status; | |||||
| } | |||||
| void sdl_audio_done(nes_Audio_Stream* stream) { | |||||
| if (stream->data) { | |||||
| SDL_CloseAudioDevice( | |||||
| ((sdl_audio_device*)stream->data)->id | |||||
| ); | |||||
| stream->data = NULL; | |||||
| } | |||||
| } | |||||
| int sdl_audio_push(nes_Audio_Stream* stream, | |||||
| short* samples, int n_samples) { | |||||
| return SDL_QueueAudio( | |||||
| ((sdl_audio_device*)stream->data)->id, | |||||
| samples, n_samples * sizeof(short) | |||||
| ); | |||||
| } | |||||
| nes_Audio_Stream sdl_audio = { | |||||
| .init = sdl_audio_init, | |||||
| .done = sdl_audio_done, | |||||
| .push = sdl_audio_push, | |||||
| }; | |||||