int main(int argc, char **argv) { StreamPlayer *player; int i; /* Print out usage if no file was specified */ if(argc < 2) { fprintf(stderr, "Usage: %s <filenames...>\n", argv[0]); return 1; } if(InitAL() != 0) return 1; if(alIsExtensionPresent("AL_SOFT_buffer_samples")) { printf("AL_SOFT_buffer_samples supported!\n"); alBufferSamplesSOFT = alGetProcAddress("alBufferSamplesSOFT"); alIsBufferFormatSupportedSOFT = alGetProcAddress("alIsBufferFormatSupportedSOFT"); } else printf("AL_SOFT_buffer_samples not supported\n"); player = NewPlayer(); /* Play each file listed on the command line */ for(i = 1;i < argc;i++) { if(!OpenPlayerFile(player, argv[i])) continue; printf("Playing %s (%s, %s, %dhz)\n", argv[i], TypeName(player->type), ChannelsName(player->channels), player->rate); fflush(stdout); if(!StartPlayer(player)) { ClosePlayerFile(player); continue; } while(UpdatePlayer(player)) Sleep(10); /* All done with this file. Close it and go to the next */ ClosePlayerFile(player); } printf("Done.\n"); /* All files done. Delete the player, and close OpenAL */ DeletePlayer(player); player = NULL; CloseAL(); return 0; }
/* Opens the first audio stream of the named file. If a file is already open, * it will be closed first. */ static int OpenPlayerFile(StreamPlayer *player, const char *filename) { ClosePlayerFile(player); /* Open the file and get the first stream from it */ player->file = openAVFile(filename); player->stream = getAVAudioStream(player->file, 0); if(!player->stream) { fprintf(stderr, "Could not open audio in %s\n", filename); goto error; } /* Get the stream format, and figure out the OpenAL format */ if(getAVAudioInfo(player->stream, &player->rate, &player->channels, &player->type) != 0) { fprintf(stderr, "Error getting audio info for %s\n", filename); goto error; } player->format = GetFormat(player->channels, player->type, alIsBufferFormatSupportedSOFT); if(player->format == 0) { fprintf(stderr, "Unsupported format (%s, %s) for %s\n", ChannelsName(player->channels), TypeName(player->type), filename); goto error; } /* Allocate enough space for the temp buffer, given the format */ player->datasize = FramesToBytes(BUFFER_SIZE, player->channels, player->type); player->data = malloc(player->datasize); if(player->data == NULL) { fprintf(stderr, "Error allocating %d bytes\n", player->datasize); goto error; } return 1; error: closeAVFile(player->file); player->file = NULL; player->stream = NULL; player->datasize = 0; return 0; }
/* LoadBuffer loads the named audio file into an OpenAL buffer object, and * returns the new buffer ID. */ static ALuint LoadSound(const char *filename) { ALenum err, format, type, channels; ALuint rate, buffer; size_t datalen; void *data; FilePtr sound; /* Open the audio file */ sound = openAudioFile(filename, 1000); if(!sound) { fprintf(stderr, "Could not open audio in %s\n", filename); closeAudioFile(sound); return 0; } /* Get the sound format, and figure out the OpenAL format */ if(getAudioInfo(sound, &rate, &channels, &type) != 0) { fprintf(stderr, "Error getting audio info for %s\n", filename); closeAudioFile(sound); return 0; } format = GetFormat(channels, type, NULL); if(format == AL_NONE) { fprintf(stderr, "Unsupported format (%s, %s) for %s\n", ChannelsName(channels), TypeName(type), filename); closeAudioFile(sound); return 0; } /* Decode the whole audio stream to a buffer. */ data = decodeAudioStream(sound, &datalen); if(!data) { fprintf(stderr, "Failed to read audio from %s\n", filename); closeAudioFile(sound); return 0; } /* Buffer the audio data into a new buffer object, then free the data and * close the file. */ buffer = 0; alGenBuffers(1, &buffer); alBufferData(buffer, format, data, datalen, rate); free(data); closeAudioFile(sound); /* Check if an error occured, and clean up if so. */ err = alGetError(); if(err != AL_NO_ERROR) { fprintf(stderr, "OpenAL Error: %s\n", alGetString(err)); if(buffer && alIsBuffer(buffer)) alDeleteBuffers(1, &buffer); return 0; } return buffer; }
int main() { PlaybackInfo playback = { NULL, NULL, 0 }; SDL_AudioSpec desired, obtained; ALuint source, buffer; ALCint attrs[16]; ALenum state; /* Print out error if extension is missing. */ if(!alcIsExtensionPresent(NULL, "ALC_SOFT_loopback")) { fprintf(stderr, "Error: ALC_SOFT_loopback not supported!\n"); return 1; } /* Define a macro to help load the function pointers. */ #define LOAD_PROC(x) ((x) = alcGetProcAddress(NULL, #x)) LOAD_PROC(alcLoopbackOpenDeviceSOFT); LOAD_PROC(alcIsRenderFormatSupportedSOFT); LOAD_PROC(alcRenderSamplesSOFT); #undef LOAD_PROC if(SDL_Init(SDL_INIT_AUDIO) == -1) { fprintf(stderr, "Failed to init SDL audio: %s\n", SDL_GetError()); return 1; } /* Set up SDL audio with our requested format and callback. */ desired.channels = 2; desired.format = AUDIO_S16SYS; desired.freq = 44100; desired.padding = 0; desired.samples = 4096; desired.callback = RenderSDLSamples; desired.userdata = &playback; if(SDL_OpenAudio(&desired, &obtained) != 0) { SDL_Quit(); fprintf(stderr, "Failed to open SDL audio: %s\n", SDL_GetError()); return 1; } /* Set up our OpenAL attributes based on what we got from SDL. */ attrs[0] = ALC_FORMAT_CHANNELS_SOFT; if(obtained.channels == 1) attrs[1] = ALC_MONO_SOFT; else if(obtained.channels == 2) attrs[1] = ALC_STEREO_SOFT; else { fprintf(stderr, "Unhandled SDL channel count: %d\n", obtained.channels); goto error; } attrs[2] = ALC_FORMAT_TYPE_SOFT; if(obtained.format == AUDIO_U8) attrs[3] = ALC_UNSIGNED_BYTE_SOFT; else if(obtained.format == AUDIO_S8) attrs[3] = ALC_BYTE_SOFT; else if(obtained.format == AUDIO_U16SYS) attrs[3] = ALC_UNSIGNED_SHORT_SOFT; else if(obtained.format == AUDIO_S16SYS) attrs[3] = ALC_SHORT_SOFT; else { fprintf(stderr, "Unhandled SDL format: 0x%04x\n", obtained.format); goto error; } attrs[4] = ALC_FREQUENCY; attrs[5] = obtained.freq; attrs[6] = 0; /* end of list */ /* Initialize OpenAL loopback device, using our format attributes. */ playback.Device = alcLoopbackOpenDeviceSOFT(NULL); if(!playback.Device) { fprintf(stderr, "Failed to open loopback device!\n"); goto error; } /* Make sure the format is supported before setting them on the device. */ if(alcIsRenderFormatSupportedSOFT(playback.Device, attrs[5], attrs[1], attrs[3]) == ALC_FALSE) { fprintf(stderr, "Render format not supported: %s, %s, %dhz\n", ChannelsName(attrs[1]), TypeName(attrs[3]), attrs[5]); goto error; } playback.Context = alcCreateContext(playback.Device, attrs); if(!playback.Context || alcMakeContextCurrent(playback.Context) == ALC_FALSE) { fprintf(stderr, "Failed to set an OpenAL audio context\n"); goto error; } playback.FrameSize = FramesToBytes(1, attrs[1], attrs[3]); /* Start SDL playing. Our callback (thus alcRenderSamplesSOFT) will now * start being called regularly to update the AL playback state. */ SDL_PauseAudio(0); /* Load the sound into a buffer. */ buffer = CreateSineWave(); if(!buffer) { SDL_CloseAudio(); alcDestroyContext(playback.Context); alcCloseDevice(playback.Device); SDL_Quit(); return 1; } /* Create the source to play the sound with. */ source = 0; alGenSources(1, &source); alSourcei(source, AL_BUFFER, buffer); assert(alGetError()==AL_NO_ERROR && "Failed to setup sound source"); /* Play the sound until it finishes. */ alSourcePlay(source); do { Sleep(10); alGetSourcei(source, AL_SOURCE_STATE, &state); } while(alGetError() == AL_NO_ERROR && state == AL_PLAYING); /* All done. Delete resources, and close OpenAL. */ alDeleteSources(1, &source); alDeleteBuffers(1, &buffer); /* Stop SDL playing. */ SDL_PauseAudio(1); /* Close up OpenAL and SDL. */ SDL_CloseAudio(); alcDestroyContext(playback.Context); alcCloseDevice(playback.Device); SDL_Quit(); return 0; error: SDL_CloseAudio(); if(playback.Context) alcDestroyContext(playback.Context); if(playback.Device) alcCloseDevice(playback.Device); SDL_Quit(); return 1; }