src/audio/SDL_mixer.c
author Patrice Mandin <patmandin@gmail.com>
Tue, 03 Jun 2003 19:35:10 +0000
changeset 633 873c2598f969
parent 574 64fe373be3dc
child 739 22dbf364c017
permissions -rw-r--r--
Add m68k assembly mixing routines
     1 /*
     2     SDL - Simple DirectMedia Layer
     3     Copyright (C) 1997, 1998, 1999, 2000, 2001, 2002  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 
    23 #ifdef SAVE_RCSID
    24 static char rcsid =
    25  "@(#) $Id$";
    26 #endif
    27 
    28 /* This provides the default mixing callback for the SDL audio routines */
    29 
    30 #include <stdio.h>
    31 #include <stdlib.h>
    32 #include <string.h>
    33 
    34 #include "SDL_audio.h"
    35 #include "SDL_mutex.h"
    36 #include "SDL_timer.h"
    37 #include "SDL_sysaudio.h"
    38 #include "SDL_mixer_MMX.h"
    39 #include "SDL_mixer_MMX_VC.h"
    40 #include "SDL_mixer_m68k.h"
    41 
    42 /* Function to check the CPU flags */
    43 #define MMX_CPU		0x800000
    44 #ifdef USE_ASMBLIT
    45 #define CPU_Flags()	Hermes_X86_CPU()
    46 #else
    47 #define CPU_Flags()	0L
    48 #endif
    49 
    50 #ifdef USE_ASMBLIT
    51 #define X86_ASSEMBLER
    52 #define HermesConverterInterface	void
    53 #define HermesClearInterface		void
    54 #define STACKCALL
    55 
    56 #include "HeadX86.h"
    57 #endif
    58 
    59 /* This table is used to add two sound values together and pin
    60  * the value to avoid overflow.  (used with permission from ARDI)
    61  * Changed to use 0xFE instead of 0xFF for better sound quality.
    62  */
    63 static const Uint8 mix8[] =
    64 {
    65   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    66   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    67   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    68   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    69   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    70   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    71   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    72   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    73   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    74   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    75   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
    76   0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x02, 0x03,
    77   0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E,
    78   0x0F, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19,
    79   0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F, 0x20, 0x21, 0x22, 0x23, 0x24,
    80   0x25, 0x26, 0x27, 0x28, 0x29, 0x2A, 0x2B, 0x2C, 0x2D, 0x2E, 0x2F,
    81   0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3A,
    82   0x3B, 0x3C, 0x3D, 0x3E, 0x3F, 0x40, 0x41, 0x42, 0x43, 0x44, 0x45,
    83   0x46, 0x47, 0x48, 0x49, 0x4A, 0x4B, 0x4C, 0x4D, 0x4E, 0x4F, 0x50,
    84   0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5A, 0x5B,
    85   0x5C, 0x5D, 0x5E, 0x5F, 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66,
    86   0x67, 0x68, 0x69, 0x6A, 0x6B, 0x6C, 0x6D, 0x6E, 0x6F, 0x70, 0x71,
    87   0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7A, 0x7B, 0x7C,
    88   0x7D, 0x7E, 0x7F, 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87,
    89   0x88, 0x89, 0x8A, 0x8B, 0x8C, 0x8D, 0x8E, 0x8F, 0x90, 0x91, 0x92,
    90   0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99, 0x9A, 0x9B, 0x9C, 0x9D,
    91   0x9E, 0x9F, 0xA0, 0xA1, 0xA2, 0xA3, 0xA4, 0xA5, 0xA6, 0xA7, 0xA8,
    92   0xA9, 0xAA, 0xAB, 0xAC, 0xAD, 0xAE, 0xAF, 0xB0, 0xB1, 0xB2, 0xB3,
    93   0xB4, 0xB5, 0xB6, 0xB7, 0xB8, 0xB9, 0xBA, 0xBB, 0xBC, 0xBD, 0xBE,
    94   0xBF, 0xC0, 0xC1, 0xC2, 0xC3, 0xC4, 0xC5, 0xC6, 0xC7, 0xC8, 0xC9,
    95   0xCA, 0xCB, 0xCC, 0xCD, 0xCE, 0xCF, 0xD0, 0xD1, 0xD2, 0xD3, 0xD4,
    96   0xD5, 0xD6, 0xD7, 0xD8, 0xD9, 0xDA, 0xDB, 0xDC, 0xDD, 0xDE, 0xDF,
    97   0xE0, 0xE1, 0xE2, 0xE3, 0xE4, 0xE5, 0xE6, 0xE7, 0xE8, 0xE9, 0xEA,
    98   0xEB, 0xEC, 0xED, 0xEE, 0xEF, 0xF0, 0xF1, 0xF2, 0xF3, 0xF4, 0xF5,
    99   0xF6, 0xF7, 0xF8, 0xF9, 0xFA, 0xFB, 0xFC, 0xFD, 0xFE, 0xFE, 0xFE,
   100   0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE,
   101   0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE,
   102   0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE,
   103   0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE,
   104   0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE,
   105   0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE,
   106   0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE,
   107   0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE,
   108   0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE,
   109   0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE,
   110   0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE,
   111   0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE
   112 };
   113 
   114 /* The volume ranges from 0 - 128 */
   115 #define ADJUST_VOLUME(s, v)	(s = (s*v)/SDL_MIX_MAXVOLUME)
   116 #define ADJUST_VOLUME_U8(s, v)	(s = (((s-128)*v)/SDL_MIX_MAXVOLUME)+128)
   117 
   118 void SDL_MixAudio (Uint8 *dst, const Uint8 *src, Uint32 len, int volume)
   119 {
   120 	Uint16 format;
   121 
   122 	if ( volume == 0 ) {
   123 		return;
   124 	}
   125 	/* Mix the user-level audio format */
   126 	if ( current_audio ) {
   127 		if ( current_audio->convert.needed ) {
   128 			format = current_audio->convert.src_format;
   129 		} else {
   130 			format = current_audio->spec.format;
   131 		}
   132 	} else {
   133   		/* HACK HACK HACK */
   134 		format = AUDIO_S16;
   135 	}
   136 	switch (format) {
   137 
   138 		case AUDIO_U8: {
   139 #if defined(__M68000__) && defined(__GNUC__)
   140 			SDL_MixAudio_m68k_U8((char*)dst,(char*)src,(unsigned long)len,(long)volume,(char *)mix8);
   141 #else
   142 			Uint8 src_sample;
   143 
   144 			while ( len-- ) {
   145 				src_sample = *src;
   146 				ADJUST_VOLUME_U8(src_sample, volume);
   147 				*dst = mix8[*dst+src_sample];
   148 				++dst;
   149 				++src;
   150 			}
   151 #endif
   152 		}
   153 		break;
   154 
   155 		case AUDIO_S8: {
   156 #if defined(i386) && defined(__GNUC__) && defined(USE_ASMBLIT)
   157 			if (CPU_Flags() & MMX_CPU)
   158 			{
   159 				SDL_MixAudio_MMX_S8((char*)dst,(char*)src,(unsigned int)len,(int)volume);
   160 			}
   161 			else
   162 #endif
   163 #if defined(USE_ASM_MIXER_VC)
   164 			if (SDL_IsMMX_VC())
   165 			{
   166 				SDL_MixAudio_MMX_S8_VC((char*)dst,(char*)src,(unsigned int)len,(int)volume);
   167 			}
   168 			else
   169 #endif
   170 #if defined(__M68000__) && defined(__GNUC__)
   171 			SDL_MixAudio_m68k_S8((char*)dst,(char*)src,(unsigned long)len,(long)volume);
   172 #else
   173 			{
   174 			Sint8 *dst8, *src8;
   175 			Sint8 src_sample;
   176 			int dst_sample;
   177 			const int max_audioval = ((1<<(8-1))-1);
   178 			const int min_audioval = -(1<<(8-1));
   179 
   180 			src8 = (Sint8 *)src;
   181 			dst8 = (Sint8 *)dst;
   182 			while ( len-- ) {
   183 				src_sample = *src8;
   184 				ADJUST_VOLUME(src_sample, volume);
   185 				dst_sample = *dst8 + src_sample;
   186 				if ( dst_sample > max_audioval ) {
   187 					*dst8 = max_audioval;
   188 				} else
   189 				if ( dst_sample < min_audioval ) {
   190 					*dst8 = min_audioval;
   191 				} else {
   192 					*dst8 = dst_sample;
   193 				}
   194 				++dst8;
   195 				++src8;
   196 			}
   197 			}
   198 #endif
   199 		}
   200 		break;
   201 
   202 		case AUDIO_S16LSB: {
   203 #if defined(i386) && defined(__GNUC__) && defined(USE_ASMBLIT)
   204 			if (CPU_Flags() & MMX_CPU)
   205 			{
   206 				SDL_MixAudio_MMX_S16((char*)dst,(char*)src,(unsigned int)len,(int)volume);
   207 			}
   208 			else
   209 #elif defined(USE_ASM_MIXER_VC)
   210 			if (SDL_IsMMX_VC())
   211 			{
   212 				SDL_MixAudio_MMX_S16_VC((char*)dst,(char*)src,(unsigned int)len,(int)volume);
   213 			}
   214 			else
   215 #endif
   216 #if defined(__M68000__) && defined(__GNUC__)
   217 			SDL_MixAudio_m68k_S16LSB((short*)dst,(short*)src,(unsigned long)len,(long)volume);
   218 #else
   219 			{
   220 			Sint16 src1, src2;
   221 			int dst_sample;
   222 			const int max_audioval = ((1<<(16-1))-1);
   223 			const int min_audioval = -(1<<(16-1));
   224 
   225 			len /= 2;
   226 			while ( len-- ) {
   227 				src1 = ((src[1])<<8|src[0]);
   228 				ADJUST_VOLUME(src1, volume);
   229 				src2 = ((dst[1])<<8|dst[0]);
   230 				src += 2;
   231 				dst_sample = src1+src2;
   232 				if ( dst_sample > max_audioval ) {
   233 					dst_sample = max_audioval;
   234 				} else
   235 				if ( dst_sample < min_audioval ) {
   236 					dst_sample = min_audioval;
   237 				}
   238 				dst[0] = dst_sample&0xFF;
   239 				dst_sample >>= 8;
   240 				dst[1] = dst_sample&0xFF;
   241 				dst += 2;
   242 			}
   243 			}
   244 #endif
   245 		}
   246 		break;
   247 
   248 		case AUDIO_S16MSB: {
   249 #if defined(__M68000__) && defined(__GNUC__)
   250 			SDL_MixAudio_m68k_S16MSB((short*)dst,(short*)src,(unsigned long)len,(long)volume);
   251 #else
   252 			Sint16 src1, src2;
   253 			int dst_sample;
   254 			const int max_audioval = ((1<<(16-1))-1);
   255 			const int min_audioval = -(1<<(16-1));
   256 
   257 			len /= 2;
   258 			while ( len-- ) {
   259 				src1 = ((src[0])<<8|src[1]);
   260 				ADJUST_VOLUME(src1, volume);
   261 				src2 = ((dst[0])<<8|dst[1]);
   262 				src += 2;
   263 				dst_sample = src1+src2;
   264 				if ( dst_sample > max_audioval ) {
   265 					dst_sample = max_audioval;
   266 				} else
   267 				if ( dst_sample < min_audioval ) {
   268 					dst_sample = min_audioval;
   269 				}
   270 				dst[1] = dst_sample&0xFF;
   271 				dst_sample >>= 8;
   272 				dst[0] = dst_sample&0xFF;
   273 				dst += 2;
   274 			}
   275 #endif
   276 		}
   277 		break;
   278 
   279 		default: /* If this happens... FIXME! */
   280 			SDL_SetError("SDL_MixAudio(): unknown audio format");
   281 			return;
   282 	}
   283 }
   284