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