Created
October 16, 2017 17:24
-
-
Save wutipong/053131074621928602441aa0f5b1d1d8 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/************************************************************************** | |
* AlStream : Play streaming OGG file with custom loop points. | |
* License : Public Domain. | |
* Usage: alStream input.ogg | |
* | |
* Note: | |
* | |
* The input file will be played infintely until the program close. If the | |
* input file has the `loop_end` comment in its header, the file will be played | |
* to that point then loop back to start. If the input file has the `loop_start` | |
* comment in its header, the file will be loop to that point instead of the | |
* begining of the file. | |
* | |
* *************************************************************************/ | |
#include <AL/al.h> | |
#include <AL/alc.h> | |
#include <SDL.h> | |
#include <vorbis/codec.h> | |
#include <vorbis/vorbisfile.h> | |
constexpr int BUFFER_COUNT = 3; | |
constexpr int BUFFER_SIZE = 64 * 1024; | |
constexpr int FREQUENCY = 44100; | |
void fillBuffer(OggVorbis_File *pVf, const ALuint &alBuffer, | |
const int &channels, const long &rate, | |
const long int &start_loop, const long int &end_loop) { | |
int bitstream; | |
int read_total = 0; | |
char buffer[BUFFER_SIZE]; | |
while (true) { | |
if (read_total >= BUFFER_SIZE) | |
break; | |
auto pos = ov_pcm_tell(pVf); | |
if (pos > end_loop) | |
ov_pcm_seek(pVf, start_loop); | |
int read = ov_read(pVf, buffer + read_total, BUFFER_SIZE - read_total, 0, 2, | |
1, &bitstream); | |
read_total += read; | |
} | |
alBufferData(alBuffer, | |
(channels == 1) ? AL_FORMAT_MONO16 : AL_FORMAT_STEREO16, buffer, | |
read_total, rate); | |
} | |
int main(int argc, char **argv) { | |
if (argc != 2) | |
return -1; | |
SDL_Init(SDL_INIT_VIDEO); | |
SDL_Window *pWindow; | |
SDL_Renderer *pRenderer; | |
SDL_CreateWindowAndRenderer(800, 600, 0, &pWindow, &pRenderer); | |
SDL_SetWindowTitle(pWindow, "Test"); | |
auto alcDevice = alcOpenDevice(NULL); | |
auto alcContext = alcCreateContext(alcDevice, NULL); | |
alcMakeContextCurrent(alcContext); | |
ALuint source; | |
alGenSources(1, &source); | |
ALuint buffers[BUFFER_COUNT]; | |
alGenBuffers(BUFFER_COUNT, buffers); | |
OggVorbis_File vf; | |
ov_fopen(argv[1], &vf); | |
auto info = ov_info(&vf, -1); | |
auto comment = ov_comment(&vf, -1); | |
auto loop_start_cmt = vorbis_comment_query(comment, "loop_start", 0); | |
auto loop_end_cmt = vorbis_comment_query(comment, "loop_end", 0); | |
auto loop_start = loop_start_cmt ? atol(loop_start_cmt) : 0L; | |
auto loop_end = loop_end_cmt ? atol(loop_end_cmt) : ov_pcm_total(&vf, -1); | |
for (auto buffer : buffers) { | |
fillBuffer(&vf, buffer, info->channels, info->rate, loop_start, loop_end); | |
} | |
alSourceQueueBuffers(source, BUFFER_COUNT, buffers); | |
alSourcePlay(source); | |
int currentBufferIndex = 0; | |
int bufferProcessed = 0; | |
while (true) { | |
SDL_Event event; | |
SDL_PollEvent(&event); | |
if (event.type == SDL_QUIT) | |
break; | |
SDL_Delay(10); | |
SDL_RenderPresent(pRenderer); | |
int processed; | |
alGetSourcei(source, AL_BUFFERS_PROCESSED, &processed); | |
if (processed != bufferProcessed) { | |
int count = processed - bufferProcessed; | |
for (int i = 0; i < count; i++) { | |
currentBufferIndex++; | |
if (currentBufferIndex == BUFFER_COUNT) | |
currentBufferIndex = 0; | |
alDeleteBuffers(1, &buffers[currentBufferIndex]); | |
alGenBuffers(1, &buffers[currentBufferIndex]); | |
fillBuffer(&vf, buffers[currentBufferIndex], info->channels, info->rate, | |
loop_start, loop_end); | |
alSourceQueueBuffers(source, 1, &buffers[currentBufferIndex]); | |
} | |
bufferProcessed = processed; | |
} | |
} | |
alcDestroyContext(alcContext); | |
alcCloseDevice(alcDevice); | |
ov_clear(&vf); | |
SDL_DestroyRenderer(pRenderer); | |
SDL_DestroyWindow(pWindow); | |
SDL_Quit(); | |
return 0; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment