// // Copyright(C) 2005-2014 Simon Howard // // This program is free software; you can redistribute it and/or // modify it under the terms of the GNU General Public License // as published by the Free Software Foundation; either version 2 // of the License, or (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // DESCRIPTION: // PC speaker interface. // #include #include #include "SDL.h" #include "SDL_mixer.h" #include "pcsound.h" #include "pcsound_internal.h" #define MAX_SOUND_SLICE_TIME 70 /* ms */ #define SQUARE_WAVE_AMP 0x2000 // If true, we initialized SDL and have the responsibility to shut it // down static int sdl_was_initialized = 0; // Callback function to invoke when we want new sound data static pcsound_callback_func callback; // Output sound format static int mixing_freq; static Uint16 mixing_format; static int mixing_channels; // Currently playing sound // current_remaining is the number of remaining samples that must be played // before we invoke the callback to get the next frequency. static int current_remaining; static int current_freq; static int phase_offset = 0; // Mixer function that does the PC speaker emulation static void PCSound_Mix_Callback(void *udata, Uint8 *stream, int len) { Sint16 *leftptr; Sint16 *rightptr; Sint16 this_value; int oldfreq; int i; int nsamples; // Number of samples is quadrupled, because of 16-bit and stereo nsamples = len / 4; leftptr = (Sint16 *) stream; rightptr = ((Sint16 *) stream) + 1; // Fill the output buffer for (i=0; i limit) { return (1 << n); } } // Should never happen? return 1024; } static int PCSound_SDL_Init(pcsound_callback_func callback_func) { int slicesize; // Check if SDL_mixer has been opened already // If not, we must initialize it now if (!SDLIsInitialized()) { if (SDL_Init(SDL_INIT_AUDIO) < 0) { fprintf(stderr, "Unable to set up sound.\n"); return 0; } slicesize = GetSliceSize(); if (Mix_OpenAudio(pcsound_sample_rate, AUDIO_S16SYS, 2, slicesize) < 0) { fprintf(stderr, "Error initializing SDL_mixer: %s\n", Mix_GetError()); SDL_QuitSubSystem(SDL_INIT_AUDIO); return 0; } SDL_PauseAudio(0); // When this module shuts down, it has the responsibility to // shut down SDL. sdl_was_initialized = 1; } // Get the mixer frequency, format and number of channels. Mix_QuerySpec(&mixing_freq, &mixing_format, &mixing_channels); // Only supports AUDIO_S16SYS if (mixing_format != AUDIO_S16SYS || mixing_channels != 2) { fprintf(stderr, "PCSound_SDL only supports native signed 16-bit LSB, " "stereo format!\n"); PCSound_SDL_Shutdown(); return 0; } callback = callback_func; current_freq = 0; current_remaining = 0; Mix_SetPostMix(PCSound_Mix_Callback, NULL); return 1; } pcsound_driver_t pcsound_sdl_driver = { "SDL", PCSound_SDL_Init, PCSound_SDL_Shutdown, };