1 /* 2 SDL - Simple DirectMedia Layer 3 Copyright (C) 1997-2012 Sam Lantinga 4 5 This library is free software; you can redistribute it and/or 6 modify it under the terms of the GNU Lesser General Public 7 License as published by the Free Software Foundation; either 8 version 2.1 of the License, or (at your option) any later version. 9 10 This library is distributed in the hope that it will be useful, 11 but WITHOUT ANY WARRANTY; without even the implied warranty of 12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 13 Lesser General Public License for more details. 14 15 You should have received a copy of the GNU Lesser General Public 16 License along with this library; if not, write to the Free Software 17 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA 18 19 Sam Lantinga 20 slouken (at) libsdl.org 21 22 This file written by Ryan C. Gordon (icculus (at) icculus.org) 23 */ 24 #include "SDL_config.h" 25 26 /* Output raw audio data to a file. */ 27 28 #if HAVE_STDIO_H 29 #include <stdio.h> 30 #endif 31 32 #include "SDL_rwops.h" 33 #include "SDL_timer.h" 34 #include "SDL_audio.h" 35 #include "../SDL_audiomem.h" 36 #include "../SDL_audio_c.h" 37 #include "../SDL_audiodev_c.h" 38 #include "SDL_diskaudio.h" 39 40 /* The tag name used by DISK audio */ 41 #define DISKAUD_DRIVER_NAME "disk" 42 43 /* environment variables and defaults. */ 44 #define DISKENVR_OUTFILE "SDL_DISKAUDIOFILE" 45 #define DISKDEFAULT_OUTFILE "sdlaudio.raw" 46 #define DISKENVR_WRITEDELAY "SDL_DISKAUDIODELAY" 47 #define DISKDEFAULT_WRITEDELAY 150 48 49 /* Audio driver functions */ 50 static int DISKAUD_OpenAudio(_THIS, SDL_AudioSpec *spec); 51 static void DISKAUD_WaitAudio(_THIS); 52 static void DISKAUD_PlayAudio(_THIS); 53 static Uint8 *DISKAUD_GetAudioBuf(_THIS); 54 static void DISKAUD_CloseAudio(_THIS); 55 56 static const char *DISKAUD_GetOutputFilename(void) 57 { 58 const char *envr = SDL_getenv(DISKENVR_OUTFILE); 59 return((envr != NULL) ? envr : DISKDEFAULT_OUTFILE); 60 } 61 62 /* Audio driver bootstrap functions */ 63 static int DISKAUD_Available(void) 64 { 65 const char *envr = SDL_getenv("SDL_AUDIODRIVER"); 66 if (envr && (SDL_strcmp(envr, DISKAUD_DRIVER_NAME) == 0)) { 67 return(1); 68 } 69 return(0); 70 } 71 72 static void DISKAUD_DeleteDevice(SDL_AudioDevice *device) 73 { 74 SDL_free(device->hidden); 75 SDL_free(device); 76 } 77 78 static SDL_AudioDevice *DISKAUD_CreateDevice(int devindex) 79 { 80 SDL_AudioDevice *this; 81 const char *envr; 82 83 /* Initialize all variables that we clean on shutdown */ 84 this = (SDL_AudioDevice *)SDL_malloc(sizeof(SDL_AudioDevice)); 85 if ( this ) { 86 SDL_memset(this, 0, (sizeof *this)); 87 this->hidden = (struct SDL_PrivateAudioData *) 88 SDL_malloc((sizeof *this->hidden)); 89 } 90 if ( (this == NULL) || (this->hidden == NULL) ) { 91 SDL_OutOfMemory(); 92 if ( this ) { 93 SDL_free(this); 94 } 95 return(0); 96 } 97 SDL_memset(this->hidden, 0, (sizeof *this->hidden)); 98 99 envr = SDL_getenv(DISKENVR_WRITEDELAY); 100 this->hidden->write_delay = (envr) ? SDL_atoi(envr) : DISKDEFAULT_WRITEDELAY; 101 102 /* Set the function pointers */ 103 this->OpenAudio = DISKAUD_OpenAudio; 104 this->WaitAudio = DISKAUD_WaitAudio; 105 this->PlayAudio = DISKAUD_PlayAudio; 106 this->GetAudioBuf = DISKAUD_GetAudioBuf; 107 this->CloseAudio = DISKAUD_CloseAudio; 108 109 this->free = DISKAUD_DeleteDevice; 110 111 return this; 112 } 113 114 AudioBootStrap DISKAUD_bootstrap = { 115 DISKAUD_DRIVER_NAME, "direct-to-disk audio", 116 DISKAUD_Available, DISKAUD_CreateDevice 117 }; 118 119 /* This function waits until it is possible to write a full sound buffer */ 120 static void DISKAUD_WaitAudio(_THIS) 121 { 122 SDL_Delay(this->hidden->write_delay); 123 } 124 125 static void DISKAUD_PlayAudio(_THIS) 126 { 127 int written; 128 129 /* Write the audio data */ 130 written = SDL_RWwrite(this->hidden->output, 131 this->hidden->mixbuf, 1, 132 this->hidden->mixlen); 133 134 /* If we couldn't write, assume fatal error for now */ 135 if ( (Uint32)written != this->hidden->mixlen ) { 136 this->enabled = 0; 137 } 138 #ifdef DEBUG_AUDIO 139 fprintf(stderr, "Wrote %d bytes of audio data\n", written); 140 #endif 141 } 142 143 static Uint8 *DISKAUD_GetAudioBuf(_THIS) 144 { 145 return(this->hidden->mixbuf); 146 } 147 148 static void DISKAUD_CloseAudio(_THIS) 149 { 150 if ( this->hidden->mixbuf != NULL ) { 151 SDL_FreeAudioMem(this->hidden->mixbuf); 152 this->hidden->mixbuf = NULL; 153 } 154 if ( this->hidden->output != NULL ) { 155 SDL_RWclose(this->hidden->output); 156 this->hidden->output = NULL; 157 } 158 } 159 160 static int DISKAUD_OpenAudio(_THIS, SDL_AudioSpec *spec) 161 { 162 const char *fname = DISKAUD_GetOutputFilename(); 163 164 /* Open the audio device */ 165 this->hidden->output = SDL_RWFromFile(fname, "wb"); 166 if ( this->hidden->output == NULL ) { 167 return(-1); 168 } 169 170 #if HAVE_STDIO_H 171 fprintf(stderr, "WARNING: You are using the SDL disk writer" 172 " audio driver!\n Writing to file [%s].\n", fname); 173 #endif 174 175 /* Allocate mixing buffer */ 176 this->hidden->mixlen = spec->size; 177 this->hidden->mixbuf = (Uint8 *) SDL_AllocAudioMem(this->hidden->mixlen); 178 if ( this->hidden->mixbuf == NULL ) { 179 return(-1); 180 } 181 SDL_memset(this->hidden->mixbuf, spec->silence, spec->size); 182 183 /* We're ready to rock and roll. :-) */ 184 return(0); 185 } 186 187