src/timer/SDL_timer.c
author Ryan C. Gordon <icculus@icculus.org>
Tue, 27 Sep 2005 12:14:17 +0000
changeset 1147 b580f7201543
parent 1117 95b261f445b1
child 1190 173c063d4f55
permissions -rw-r--r--
From: "Alex Volkov" <avcp-sdlmail@usa.net>
To: "'A list for developers using the SDL library. \(includesSDL-announce\)'" <sdl@libsdl.org>
Date: Mon, 19 Sep 2005 18:59:43 -0400
Subject: [SDL] [patch] Volume multiplier bug in

The volume multiplier in SDL_MixAudio_MMX_S8() is formed from the wrong
register.
     1 /*
     2     SDL - Simple DirectMedia Layer
     3     Copyright (C) 1997, 1998  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     5635-34 Springhouse Dr.
    21     Pleasanton, CA 94588 (USA)
    22     slouken@libsdl.org
    23 */
    24 
    25 #ifdef SAVE_RCSID
    26 static char rcsid =
    27  "@(#) $Id$";
    28 #endif
    29 
    30 #include <stdlib.h>
    31 #include <stdio.h>			/* For the definition of NULL */
    32 
    33 #include "SDL_error.h"
    34 #include "SDL_timer.h"
    35 #include "SDL_timer_c.h"
    36 #include "SDL_mutex.h"
    37 #include "SDL_systimer.h"
    38 
    39 /* #define DEBUG_TIMERS */
    40 
    41 int SDL_timer_started = 0;
    42 int SDL_timer_running = 0;
    43 
    44 /* Data to handle a single periodic alarm */
    45 Uint32 SDL_alarm_interval = 0;
    46 SDL_TimerCallback SDL_alarm_callback;
    47 
    48 /* Data used for a thread-based timer */
    49 static int SDL_timer_threaded = 0;
    50 
    51 struct _SDL_TimerID {
    52 	Uint32 interval;
    53 	SDL_NewTimerCallback cb;
    54 	void *param;
    55 	Uint32 last_alarm;
    56 	struct _SDL_TimerID *next;
    57 };
    58 
    59 static SDL_TimerID SDL_timers = NULL;
    60 static SDL_mutex *SDL_timer_mutex;
    61 static volatile SDL_bool list_changed = SDL_FALSE;
    62 
    63 /* Set whether or not the timer should use a thread.
    64    This should not be called while the timer subsystem is running.
    65 */
    66 int SDL_SetTimerThreaded(int value)
    67 {
    68 	int retval;
    69 
    70 	if ( SDL_timer_started ) {
    71 		SDL_SetError("Timer already initialized");
    72 		retval = -1;
    73 	} else {
    74 		retval = 0;
    75 		SDL_timer_threaded = value;
    76 	}
    77 	return retval;
    78 }
    79 
    80 int SDL_TimerInit(void)
    81 {
    82 	int retval;
    83 
    84 	retval = 0;
    85 	if ( SDL_timer_started ) {
    86 		SDL_TimerQuit();
    87 	}
    88 	if ( ! SDL_timer_threaded ) {
    89 		retval = SDL_SYS_TimerInit();
    90 	}
    91 	if ( SDL_timer_threaded ) {
    92 		SDL_timer_mutex = SDL_CreateMutex();
    93 	}
    94 	if ( retval == 0 ) {
    95 		SDL_timer_started = 1;
    96 	}
    97 	return(retval);
    98 }
    99 
   100 void SDL_TimerQuit(void)
   101 {
   102 	SDL_SetTimer(0, NULL);
   103 	if ( SDL_timer_threaded < 2 ) {
   104 		SDL_SYS_TimerQuit();
   105 	}
   106 	if ( SDL_timer_threaded ) {
   107 		SDL_DestroyMutex(SDL_timer_mutex);
   108 	}
   109 	SDL_timer_started = 0;
   110 	SDL_timer_threaded = 0;
   111 }
   112 
   113 void SDL_ThreadedTimerCheck(void)
   114 {
   115 	Uint32 now, ms;
   116 	SDL_TimerID t, prev, next;
   117 	SDL_bool removed;
   118 
   119 	SDL_mutexP(SDL_timer_mutex);
   120 	list_changed = SDL_FALSE;
   121 	now = SDL_GetTicks();
   122 	for ( prev = NULL, t = SDL_timers; t; t = next ) {
   123 		removed = SDL_FALSE;
   124 		ms = t->interval - SDL_TIMESLICE;
   125 		next = t->next;
   126 		if ( (int)(now - t->last_alarm) > (int)ms ) {
   127 			struct _SDL_TimerID timer;
   128 
   129 			if ( (now - t->last_alarm) < t->interval ) {
   130 				t->last_alarm += t->interval;
   131 			} else {
   132 				t->last_alarm = now;
   133 			}
   134 #ifdef DEBUG_TIMERS
   135 			printf("Executing timer %p (thread = %d)\n",
   136 				t, SDL_ThreadID());
   137 #endif
   138 			timer = *t;
   139 			SDL_mutexV(SDL_timer_mutex);
   140 			ms = timer.cb(timer.interval, timer.param);
   141 			SDL_mutexP(SDL_timer_mutex);
   142 			if ( list_changed ) {
   143 				/* Abort, list of timers modified */
   144 				/* FIXME: what if ms was changed? */
   145 				break;
   146 			}
   147 			if ( ms != t->interval ) {
   148 				if ( ms ) {
   149 					t->interval = ROUND_RESOLUTION(ms);
   150 				} else {
   151 					/* Remove timer from the list */
   152 #ifdef DEBUG_TIMERS
   153 					printf("SDL: Removing timer %p\n", t);
   154 #endif
   155 					if ( prev ) {
   156 						prev->next = next;
   157 					} else {
   158 						SDL_timers = next;
   159 					}
   160 					free(t);
   161 					--SDL_timer_running;
   162 					removed = SDL_TRUE;
   163 				}
   164 			}
   165 		}
   166 		/* Don't update prev if the timer has disappeared */
   167 		if ( ! removed ) {
   168 			prev = t;
   169 		}
   170 	}
   171 	SDL_mutexV(SDL_timer_mutex);
   172 }
   173 
   174 static SDL_TimerID SDL_AddTimerInternal(Uint32 interval, SDL_NewTimerCallback callback, void *param)
   175 {
   176 	SDL_TimerID t;
   177 	t = (SDL_TimerID) malloc(sizeof(struct _SDL_TimerID));
   178 	if ( t ) {
   179 		t->interval = ROUND_RESOLUTION(interval);
   180 		t->cb = callback;
   181 		t->param = param;
   182 		t->last_alarm = SDL_GetTicks();
   183 		t->next = SDL_timers;
   184 		SDL_timers = t;
   185 		++SDL_timer_running;
   186 		list_changed = SDL_TRUE;
   187 	}
   188 #ifdef DEBUG_TIMERS
   189 	printf("SDL_AddTimer(%d) = %08x num_timers = %d\n", interval, (Uint32)t, SDL_timer_running);
   190 #endif
   191 	return t;
   192 }
   193 
   194 SDL_TimerID SDL_AddTimer(Uint32 interval, SDL_NewTimerCallback callback, void *param)
   195 {
   196 	SDL_TimerID t;
   197 	if ( ! SDL_timer_mutex ) {
   198 		if ( SDL_timer_started ) {
   199 			SDL_SetError("This platform doesn't support multiple timers");
   200 		} else {
   201 			SDL_SetError("You must call SDL_Init(SDL_INIT_TIMER) first");
   202 		}
   203 		return NULL;
   204 	}
   205 	if ( ! SDL_timer_threaded ) {
   206 		SDL_SetError("Multiple timers require threaded events!");
   207 		return NULL;
   208 	}
   209 	SDL_mutexP(SDL_timer_mutex);
   210 	t = SDL_AddTimerInternal(interval, callback, param);
   211 	SDL_mutexV(SDL_timer_mutex);
   212 	return t;
   213 }
   214 
   215 SDL_bool SDL_RemoveTimer(SDL_TimerID id)
   216 {
   217 	SDL_TimerID t, prev = NULL;
   218 	SDL_bool removed;
   219 
   220 	removed = SDL_FALSE;
   221 	SDL_mutexP(SDL_timer_mutex);
   222 	/* Look for id in the linked list of timers */
   223 	for (t = SDL_timers; t; prev=t, t = t->next ) {
   224 		if ( t == id ) {
   225 			if(prev) {
   226 				prev->next = t->next;
   227 			} else {
   228 				SDL_timers = t->next;
   229 			}
   230 			free(t);
   231 			--SDL_timer_running;
   232 			removed = SDL_TRUE;
   233 			list_changed = SDL_TRUE;
   234 			break;
   235 		}
   236 	}
   237 #ifdef DEBUG_TIMERS
   238 	printf("SDL_RemoveTimer(%08x) = %d num_timers = %d thread = %d\n", (Uint32)id, removed, SDL_timer_running, SDL_ThreadID());
   239 #endif
   240 	SDL_mutexV(SDL_timer_mutex);
   241 	return removed;
   242 }
   243 
   244 /* Old style callback functions are wrapped through this */
   245 static Uint32 callback_wrapper(Uint32 ms, void *param)
   246 {
   247 	SDL_TimerCallback func = (SDL_TimerCallback) param;
   248 	return (*func)(ms);
   249 }
   250 
   251 int SDL_SetTimer(Uint32 ms, SDL_TimerCallback callback)
   252 {
   253 	int retval;
   254 
   255 #ifdef DEBUG_TIMERS
   256 	printf("SDL_SetTimer(%d)\n", ms);
   257 #endif
   258 	retval = 0;
   259 
   260 	if ( SDL_timer_threaded ) {
   261 		SDL_mutexP(SDL_timer_mutex);
   262 	}
   263 	if ( SDL_timer_running ) {	/* Stop any currently running timer */
   264 		if ( SDL_timer_threaded ) {
   265 			while ( SDL_timers ) {
   266 				SDL_TimerID freeme = SDL_timers;
   267 				SDL_timers = SDL_timers->next;
   268 				free(freeme);
   269 			}
   270 			SDL_timer_running = 0;
   271 			list_changed = SDL_TRUE;
   272 		} else {
   273 			SDL_SYS_StopTimer();
   274 			SDL_timer_running = 0;
   275 		}
   276 	}
   277 	if ( ms ) {
   278 		if ( SDL_timer_threaded ) {
   279 			if ( SDL_AddTimerInternal(ms, callback_wrapper, (void *)callback) == NULL ) {
   280 				retval = -1;
   281 			}
   282 		} else {
   283 			SDL_timer_running = 1;
   284 			SDL_alarm_interval = ms;
   285 			SDL_alarm_callback = callback;
   286 			retval = SDL_SYS_StartTimer();
   287 		}
   288 	}
   289 	if ( SDL_timer_threaded ) {
   290 		SDL_mutexV(SDL_timer_mutex);
   291 	}
   292 
   293 	return retval;
   294 }