src/audio/mint/SDL_mintaudio.c
author Sam Lantinga
Sat, 19 Sep 2009 13:29:40 +0000
changeset 3280 00cace2d9080
parent 2859 99210400e8b9
permissions -rw-r--r--
Merged a cleaned up version of Jiang's code changes from Google Summer of Code 2009
     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 Library General Public
     7     License as published by the Free Software Foundation; either
     8     version 2 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     Library General Public License for more details.
    14 
    15     You should have received a copy of the GNU Library General Public
    16     License along with this library; if not, write to the Free
    17     Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
    18 
    19     Sam Lantinga
    20     slouken@libsdl.org
    21 */
    22 #include "SDL_config.h"
    23 
    24 /*
    25 	Audio interrupt variables and callback function
    26 
    27 	Patrice Mandin
    28 */
    29 
    30 #include <unistd.h>
    31 
    32 #include <mint/osbind.h>
    33 #include <mint/falcon.h>
    34 #include <mint/mintbind.h>
    35 #include <mint/cookie.h>
    36 
    37 #include "SDL_audio.h"
    38 #include "SDL_mintaudio.h"
    39 #include "SDL_mintaudio_stfa.h"
    40 
    41 /* The audio device */
    42 
    43 SDL_AudioDevice *SDL_MintAudio_device;
    44 Uint8 *SDL_MintAudio_audiobuf[2];       /* Pointers to buffers */
    45 unsigned long SDL_MintAudio_audiosize;  /* Length of audio buffer=spec->size */
    46 volatile unsigned short SDL_MintAudio_numbuf;   /* Buffer to play */
    47 volatile unsigned short SDL_MintAudio_mutex;
    48 volatile unsigned long SDL_MintAudio_clocktics;
    49 cookie_stfa_t *SDL_MintAudio_stfa;
    50 
    51 /* MiNT thread variables */
    52 SDL_bool SDL_MintAudio_mint_present;
    53 SDL_bool SDL_MintAudio_quit_thread;
    54 SDL_bool SDL_MintAudio_thread_finished;
    55 long SDL_MintAudio_thread_pid;
    56 
    57 /* The callback function, called by each driver whenever needed */
    58 
    59 void
    60 SDL_MintAudio_Callback(void)
    61 {
    62     Uint8 *buffer;
    63     SDL_AudioDevice *audio = SDL_MintAudio_device;
    64 
    65     buffer = SDL_MintAudio_audiobuf[SDL_MintAudio_numbuf];
    66     SDL_memset(buffer, audio->spec.silence, audio->spec.size);
    67 
    68     if (audio->paused)
    69         return;
    70 
    71     if (audio->convert.needed) {
    72         int silence;
    73 
    74         if (audio->convert.src_format == AUDIO_U8) {
    75             silence = 0x80;
    76         } else {
    77             silence = 0;
    78         }
    79         SDL_memset(audio->convert.buf, silence, audio->convert.len);
    80         audio->spec.callback(audio->spec.userdata,
    81                              (Uint8 *) audio->convert.buf,
    82                              audio->convert.len);
    83         SDL_ConvertAudio(&audio->convert);
    84         SDL_memcpy(buffer, audio->convert.buf, audio->convert.len_cvt);
    85     } else {
    86         audio->spec.callback(audio->spec.userdata, buffer, audio->spec.size);
    87     }
    88 }
    89 
    90 /* Add a new frequency/clock/predivisor to the current list */
    91 void
    92 SDL_MintAudio_AddFrequency(_THIS, Uint32 frequency, Uint32 clock,
    93                            Uint32 prediv, int gpio_bits)
    94 {
    95     int i, p;
    96 
    97     if (MINTAUDIO_freqcount == MINTAUDIO_maxfreqs) {
    98         return;
    99     }
   100 
   101     /* Search where to insert the frequency (highest first) */
   102     for (p = 0; p < MINTAUDIO_freqcount; p++) {
   103         if (frequency > MINTAUDIO_frequencies[p].frequency) {
   104             break;
   105         }
   106     }
   107 
   108     /* Put all following ones farer */
   109     if (MINTAUDIO_freqcount > 0) {
   110         for (i = MINTAUDIO_freqcount; i > p; i--) {
   111             SDL_memcpy(&MINTAUDIO_frequencies[i],
   112                        &MINTAUDIO_frequencies[i - 1],
   113                        sizeof(mint_frequency_t));
   114         }
   115     }
   116 
   117     /* And insert new one */
   118     MINTAUDIO_frequencies[p].frequency = frequency;
   119     MINTAUDIO_frequencies[p].masterclock = clock;
   120     MINTAUDIO_frequencies[p].predivisor = prediv;
   121     MINTAUDIO_frequencies[p].gpio_bits = gpio_bits;
   122 
   123     MINTAUDIO_freqcount++;
   124 }
   125 
   126 /* Search for the nearest frequency */
   127 int
   128 SDL_MintAudio_SearchFrequency(_THIS, int desired_freq)
   129 {
   130     int i;
   131 
   132     /* Only 1 freq ? */
   133     if (MINTAUDIO_freqcount == 1) {
   134         return 0;
   135     }
   136 
   137     /* Check the array */
   138     for (i = 0; i < MINTAUDIO_freqcount; i++) {
   139         if (desired_freq >= ((MINTAUDIO_frequencies[i].frequency +
   140                               MINTAUDIO_frequencies[i + 1].frequency) >> 1)) {
   141             return i;
   142         }
   143     }
   144 
   145     /* Not in the array, give the latest */
   146     return MINTAUDIO_freqcount - 1;
   147 }
   148 
   149 /* Check if FPU is present */
   150 void
   151 SDL_MintAudio_CheckFpu(void)
   152 {
   153     unsigned long cookie_fpu;
   154 
   155     SDL_MintAudio_hasfpu = 0;
   156     if (Getcookie(C__FPU, &cookie_fpu) != C_FOUND) {
   157         return;
   158     }
   159     switch ((cookie_fpu >> 16) & 0xfffe) {
   160     case 2:
   161     case 4:
   162     case 6:
   163     case 8:
   164     case 16:
   165         SDL_MintAudio_hasfpu = 1;
   166         break;
   167     }
   168 }
   169 
   170 /* The thread function, used under MiNT with xbios */
   171 int
   172 SDL_MintAudio_Thread(long param)
   173 {
   174     SndBufPtr pointers;
   175     SDL_bool buffers_filled[2] = { SDL_FALSE, SDL_FALSE };
   176 
   177     SDL_MintAudio_thread_finished = SDL_FALSE;
   178     while (!SDL_MintAudio_quit_thread) {
   179         if (Buffptr(&pointers) != 0)
   180             continue;
   181 
   182         if (((unsigned long) pointers.play >=
   183              (unsigned long) SDL_MintAudio_audiobuf[0])
   184             && ((unsigned long) pointers.play <=
   185                 (unsigned long) SDL_MintAudio_audiobuf[1])) {
   186             /* DMA is reading buffer #0, setup buffer #1 if not already done */
   187             if (!buffers_filled[1]) {
   188                 SDL_MintAudio_numbuf = 1;
   189                 SDL_MintAudio_Callback();
   190                 Setbuffer(0, SDL_MintAudio_audiobuf[1],
   191                           SDL_MintAudio_audiobuf[1] +
   192                           SDL_MintAudio_audiosize);
   193                 buffers_filled[1] = SDL_TRUE;
   194                 buffers_filled[0] = SDL_FALSE;
   195             }
   196         } else {
   197             /* DMA is reading buffer #1, setup buffer #0 if not already done */
   198             if (!buffers_filled[0]) {
   199                 SDL_MintAudio_numbuf = 0;
   200                 SDL_MintAudio_Callback();
   201                 Setbuffer(0, SDL_MintAudio_audiobuf[0],
   202                           SDL_MintAudio_audiobuf[0] +
   203                           SDL_MintAudio_audiosize);
   204                 buffers_filled[0] = SDL_TRUE;
   205                 buffers_filled[1] = SDL_FALSE;
   206             }
   207         }
   208 
   209         usleep(100);
   210     }
   211     SDL_MintAudio_thread_finished = SDL_TRUE;
   212     return 0;
   213 }
   214 
   215 void
   216 SDL_MintAudio_WaitThread(void)
   217 {
   218     if (!SDL_MintAudio_mint_present)
   219         return;
   220 
   221     if (SDL_MintAudio_thread_finished)
   222         return;
   223 
   224     SDL_MintAudio_quit_thread = SDL_TRUE;
   225     while (!SDL_MintAudio_thread_finished) {
   226         Syield();
   227     }
   228 }
   229 
   230 /* vi: set ts=4 sw=4 expandtab: */