src/audio/fusionsound/SDL_fsaudio.c
changeset 2947 fec0db6c44b7
child 3230 816a7a65a59a
equal deleted inserted replaced
2946:29e1f863a844 2947:fec0db6c44b7
       
     1 /*
       
     2     SDL - Simple DirectMedia Layer
       
     3     Copyright (C) 1997-2009 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@libsdl.org
       
    21 */
       
    22 #include "SDL_config.h"
       
    23 
       
    24 /* Allow access to a raw mixing buffer */
       
    25 
       
    26 #ifdef HAVE_SIGNAL_H
       
    27 #include <signal.h>
       
    28 #endif
       
    29 #include <unistd.h>
       
    30 
       
    31 #include "SDL_timer.h"
       
    32 #include "SDL_audio.h"
       
    33 #include "../SDL_audiomem.h"
       
    34 #include "../SDL_audio_c.h"
       
    35 #include "SDL_fsaudio.h"
       
    36 
       
    37 //#define SDL_AUDIO_DRIVER_FUSIONSOUND_DYNAMIC "libfusionsound.so"
       
    38 
       
    39 #ifdef SDL_AUDIO_DRIVER_FUSIONSOUND_DYNAMIC
       
    40 #include "SDL_name.h"
       
    41 #include "SDL_loadso.h"
       
    42 #else
       
    43 #define SDL_NAME(X)	X
       
    44 #endif
       
    45 
       
    46 /* The tag name used by fusionsoundc audio */
       
    47 #define SDL_FS_DRIVER_NAME         "fusionsound"
       
    48 /* Buffers to use - more than 2 gives a lot of latency */
       
    49 #define FUSION_BUFFERS				(2)
       
    50 
       
    51 #ifdef SDL_AUDIO_DRIVER_FUSIONSOUND_DYNAMIC
       
    52 
       
    53 static const char *fs_library = SDL_AUDIO_DRIVER_FUSIONSOUND_DYNAMIC;
       
    54 static void *fs_handle = NULL;
       
    55 
       
    56 static DirectResult(*SDL_NAME(FusionSoundInit)) (int *argc, char *(*argv[]));
       
    57 static DirectResult(*SDL_NAME(FusionSoundCreate)) (IFusionSound **
       
    58                                                    ret_interface);
       
    59 
       
    60 #define SDL_FS_SYM(x) { #x, (void **) (char *) &SDL_NAME(x) }
       
    61 static struct
       
    62 {
       
    63     const char *name;
       
    64     void **func;
       
    65 } fs_functions[] = {
       
    66 /* *INDENT-OFF* */
       
    67     SDL_FS_SYM(FusionSoundInit),
       
    68     SDL_FS_SYM(FusionSoundCreate),
       
    69 /* *INDENT-ON* */
       
    70 };
       
    71 
       
    72 #undef SDL_FS_SYM
       
    73 
       
    74 static void
       
    75 UnloadFusionSoundLibrary()
       
    76 {
       
    77     if (fs_handle != NULL) {
       
    78         SDL_UnloadObject(fs_handle);
       
    79         fs_handle = NULL;
       
    80     }
       
    81 }
       
    82 
       
    83 static int
       
    84 LoadFusionSoundLibrary(void)
       
    85 {
       
    86     int i, retval = -1;
       
    87 
       
    88     if (fs_handle == NULL) {
       
    89         fs_handle = SDL_LoadObject(fs_library);
       
    90         if (fs_handle != NULL) {
       
    91             retval = 0;
       
    92             for (i = 0; i < SDL_arraysize(fs_functions); ++i) {
       
    93                 *fs_functions[i].func =
       
    94                     SDL_LoadFunction(fs_handle, fs_functions[i].name);
       
    95                 if (!*fs_functions[i].func) {
       
    96                     retval = -1;
       
    97                     UnloadFusionSoundLibrary();
       
    98                     break;
       
    99                 }
       
   100             }
       
   101         }
       
   102     }
       
   103 
       
   104     return retval;
       
   105 }
       
   106 
       
   107 #else
       
   108 
       
   109 static void
       
   110 UnloadFusionSoundLibrary()
       
   111 {
       
   112     return;
       
   113 }
       
   114 
       
   115 static int
       
   116 LoadFusionSoundLibrary(void)
       
   117 {
       
   118     return 0;
       
   119 }
       
   120 
       
   121 #endif /* SDL_AUDIO_DRIVER_FUSIONSOUND_DYNAMIC */
       
   122 
       
   123 /* This function waits until it is possible to write a full sound buffer */
       
   124 static void
       
   125 SDL_FS_WaitDevice(_THIS)
       
   126 {
       
   127     this->hidden->stream->Wait(this->hidden->stream,
       
   128                                this->hidden->mixsamples);
       
   129 }
       
   130 
       
   131 static void
       
   132 SDL_FS_PlayDevice(_THIS)
       
   133 {
       
   134     DirectResult ret;
       
   135 
       
   136     ret = this->hidden->stream->Write(this->hidden->stream,
       
   137                                       this->hidden->mixbuf,
       
   138                                       this->hidden->mixsamples);
       
   139     /* If we couldn't write, assume fatal error for now */
       
   140     if (ret) {
       
   141         this->enabled = 0;
       
   142     }
       
   143 #ifdef DEBUG_AUDIO
       
   144     fprintf(stderr, "Wrote %d bytes of audio data\n", this->hidden->mixlen);
       
   145 #endif
       
   146 }
       
   147 
       
   148 static void
       
   149 SDL_FS_WaitDone(_THIS)
       
   150 {
       
   151     this->hidden->stream->Wait(this->hidden->stream,
       
   152                                this->hidden->mixsamples * FUSION_BUFFERS);
       
   153 }
       
   154 
       
   155 
       
   156 static Uint8 *
       
   157 SDL_FS_GetDeviceBuf(_THIS)
       
   158 {
       
   159     return (this->hidden->mixbuf);
       
   160 }
       
   161 
       
   162 
       
   163 static void
       
   164 SDL_FS_CloseDevice(_THIS)
       
   165 {
       
   166     if (this->hidden != NULL) {
       
   167         if (this->hidden->mixbuf != NULL) {
       
   168             SDL_FreeAudioMem(this->hidden->mixbuf);
       
   169             this->hidden->mixbuf = NULL;
       
   170         }
       
   171         if (this->hidden->stream) {
       
   172             this->hidden->stream->Release(this->hidden->stream);
       
   173             this->hidden->stream = NULL;
       
   174         }
       
   175         if (this->hidden->fs) {
       
   176             this->hidden->fs->Release(this->hidden->fs);
       
   177             this->hidden->fs = NULL;
       
   178         }
       
   179         SDL_free(this->hidden);
       
   180         this->hidden = NULL;
       
   181     }
       
   182 }
       
   183 
       
   184 
       
   185 static int
       
   186 SDL_FS_OpenDevice(_THIS, const char *devname, int iscapture)
       
   187 {
       
   188     int bytes;
       
   189     SDL_AudioFormat test_format = 0, format = 0;
       
   190     FSSampleFormat fs_format;
       
   191     FSStreamDescription desc;
       
   192     DirectResult ret;
       
   193 
       
   194     /* Initialize all variables that we clean on shutdown */
       
   195     this->hidden = (struct SDL_PrivateAudioData *)
       
   196         SDL_malloc((sizeof *this->hidden));
       
   197     if (this->hidden == NULL) {
       
   198         SDL_OutOfMemory();
       
   199         return 0;
       
   200     }
       
   201     SDL_memset(this->hidden, 0, (sizeof *this->hidden));
       
   202 
       
   203     /* Try for a closest match on audio format */
       
   204     for (test_format = SDL_FirstAudioFormat(this->spec.format);
       
   205          !format && test_format;) {
       
   206 #ifdef DEBUG_AUDIO
       
   207         fprintf(stderr, "Trying format 0x%4.4x\n", test_format);
       
   208 #endif
       
   209         switch (test_format) {
       
   210         case AUDIO_U8:
       
   211             fs_format = FSSF_U8;
       
   212             bytes = 1;
       
   213             format = 1;
       
   214             break;
       
   215         case AUDIO_S16SYS:
       
   216             fs_format = FSSF_S16;
       
   217             bytes = 2;
       
   218             format = 1;
       
   219             break;
       
   220         case AUDIO_S32SYS:
       
   221             fs_format = FSSF_S32;
       
   222             bytes = 4;
       
   223             format = 1;
       
   224             break;
       
   225         case AUDIO_F32SYS:
       
   226             fs_format = FSSF_FLOAT;
       
   227             bytes = 4;
       
   228             format = 1;
       
   229             break;
       
   230         default:
       
   231             format = 0;
       
   232             break;
       
   233         }
       
   234         if (!format) {
       
   235             test_format = SDL_NextAudioFormat();
       
   236         }
       
   237     }
       
   238 
       
   239     if (format == 0) {
       
   240         SDL_FS_CloseDevice(this);
       
   241         SDL_SetError("Couldn't find any hardware audio formats");
       
   242         return 0;
       
   243     }
       
   244     this->spec.format = test_format;
       
   245 
       
   246     /* Retrieve the main sound interface. */
       
   247     ret = SDL_NAME(FusionSoundCreate) (&this->hidden->fs);
       
   248     if (ret) {
       
   249         SDL_FS_CloseDevice(this);
       
   250         SDL_SetError("Unable to initialize FusionSound: %d", ret);
       
   251         return 0;
       
   252     }
       
   253 
       
   254     this->hidden->mixsamples = this->spec.size / bytes / this->spec.channels;
       
   255 
       
   256     /* Fill stream description. */
       
   257     desc.flags = FSSDF_SAMPLERATE | FSSDF_BUFFERSIZE |
       
   258         FSSDF_CHANNELS | FSSDF_SAMPLEFORMAT | FSSDF_PREBUFFER;
       
   259     desc.samplerate = this->spec.freq;
       
   260     desc.buffersize = this->spec.size * FUSION_BUFFERS;
       
   261     desc.channels = this->spec.channels;
       
   262     desc.prebuffer = 10;
       
   263     desc.sampleformat = fs_format;
       
   264 
       
   265     ret =
       
   266         this->hidden->fs->CreateStream(this->hidden->fs, &desc,
       
   267                                        &this->hidden->stream);
       
   268     if (ret) {
       
   269         SDL_FS_CloseDevice(this);
       
   270         SDL_SetError("Unable to create FusionSoundStream: %d", ret);
       
   271         return 0;
       
   272     }
       
   273 
       
   274     /* See what we got */
       
   275     desc.flags = FSSDF_SAMPLERATE | FSSDF_BUFFERSIZE |
       
   276         FSSDF_CHANNELS | FSSDF_SAMPLEFORMAT;
       
   277     ret = this->hidden->stream->GetDescription(this->hidden->stream, &desc);
       
   278 
       
   279     this->spec.freq = desc.samplerate;
       
   280     this->spec.size =
       
   281         desc.buffersize / FUSION_BUFFERS * bytes * desc.channels;
       
   282     this->spec.channels = desc.channels;
       
   283 
       
   284     /* Calculate the final parameters for this audio specification */
       
   285     SDL_CalculateAudioSpec(&this->spec);
       
   286 
       
   287     /* Allocate mixing buffer */
       
   288     this->hidden->mixlen = this->spec.size;
       
   289     this->hidden->mixbuf = (Uint8 *) SDL_AllocAudioMem(this->hidden->mixlen);
       
   290     if (this->hidden->mixbuf == NULL) {
       
   291         SDL_FS_CloseDevice(this);
       
   292         SDL_OutOfMemory();
       
   293         return 0;
       
   294     }
       
   295     SDL_memset(this->hidden->mixbuf, this->spec.silence, this->spec.size);
       
   296 
       
   297     /* We're ready to rock and roll. :-) */
       
   298     return 1;
       
   299 }
       
   300 
       
   301 
       
   302 static void
       
   303 SDL_FS_Deinitialize(void)
       
   304 {
       
   305     UnloadFusionSoundLibrary();
       
   306 }
       
   307 
       
   308 
       
   309 static int
       
   310 SDL_FS_Init(SDL_AudioDriverImpl * impl)
       
   311 {
       
   312     if (LoadFusionSoundLibrary() < 0) {
       
   313         return 0;
       
   314     } else {
       
   315         DirectResult ret;
       
   316 
       
   317         ret = SDL_NAME(FusionSoundInit) (NULL, NULL);
       
   318         if (ret) {
       
   319             UnloadFusionSoundLibrary();
       
   320             SDL_SetError
       
   321                 ("FusionSound: SDL_FS_init failed (FusionSoundInit: %d)",
       
   322                  ret);
       
   323             return 0;
       
   324         }
       
   325     }
       
   326 
       
   327     /* Set the function pointers */
       
   328     impl->OpenDevice = SDL_FS_OpenDevice;
       
   329     impl->PlayDevice = SDL_FS_PlayDevice;
       
   330     impl->WaitDevice = SDL_FS_WaitDevice;
       
   331     impl->GetDeviceBuf = SDL_FS_GetDeviceBuf;
       
   332     impl->CloseDevice = SDL_FS_CloseDevice;
       
   333     impl->WaitDone = SDL_FS_WaitDone;
       
   334     impl->Deinitialize = SDL_FS_Deinitialize;
       
   335     impl->OnlyHasDefaultOutputDevice = 1;
       
   336 
       
   337     return 1;
       
   338 }
       
   339 
       
   340 
       
   341 AudioBootStrap FUSIONSOUND_bootstrap = {
       
   342     SDL_FS_DRIVER_NAME, "FusionSound", SDL_FS_Init, 0
       
   343 };
       
   344 
       
   345 /* vi: set ts=4 sw=4 expandtab: */