src/mixer.cpp
branchcustombridgeheads
changeset 5649 55c8267c933f
parent 5643 3778051e8095
child 5650 aefc131bf5ce
equal deleted inserted replaced
5648:1608018c5ff2 5649:55c8267c933f
       
     1 /* $Id$ */
       
     2 
       
     3 #include "stdafx.h"
       
     4 #include "openttd.h"
       
     5 #include "mixer.h"
       
     6 
       
     7 struct MixerChannel {
       
     8 	bool active;
       
     9 
       
    10 	// pointer to allocated buffer memory
       
    11 	int8 *memory;
       
    12 
       
    13 	// current position in memory
       
    14 	uint32 pos;
       
    15 	uint32 frac_pos;
       
    16 	uint32 frac_speed;
       
    17 	uint32 samples_left;
       
    18 
       
    19 	// Mixing volume
       
    20 	uint volume_left;
       
    21 	uint volume_right;
       
    22 
       
    23 	uint flags;
       
    24 };
       
    25 
       
    26 static MixerChannel _channels[8];
       
    27 static uint32 _play_rate;
       
    28 
       
    29 
       
    30 static void mix_int8_to_int16(MixerChannel *sc, int16 *buffer, uint samples)
       
    31 {
       
    32 	int8 *b;
       
    33 	uint32 frac_pos;
       
    34 	uint32 frac_speed;
       
    35 	uint volume_left;
       
    36 	uint volume_right;
       
    37 
       
    38 	if (samples > sc->samples_left) samples = sc->samples_left;
       
    39 	sc->samples_left -= samples;
       
    40 	assert(samples > 0);
       
    41 
       
    42 	b = sc->memory + sc->pos;
       
    43 	frac_pos = sc->frac_pos;
       
    44 	frac_speed = sc->frac_speed;
       
    45 	volume_left = sc->volume_left;
       
    46 	volume_right = sc->volume_right;
       
    47 
       
    48 	if (frac_speed == 0x10000) {
       
    49 		// Special case when frac_speed is 0x10000
       
    50 		do {
       
    51 			buffer[0] += *b * volume_left >> 8;
       
    52 			buffer[1] += *b * volume_right >> 8;
       
    53 			b++;
       
    54 			buffer += 2;
       
    55 		} while (--samples > 0);
       
    56 	} else {
       
    57 		do {
       
    58 			buffer[0] += *b * volume_left >> 8;
       
    59 			buffer[1] += *b * volume_right >> 8;
       
    60 			buffer += 2;
       
    61 			frac_pos += frac_speed;
       
    62 			b += frac_pos >> 16;
       
    63 			frac_pos &= 0xffff;
       
    64 		} while (--samples > 0);
       
    65 	}
       
    66 
       
    67 	sc->frac_pos = frac_pos;
       
    68 	sc->pos = b - sc->memory;
       
    69 }
       
    70 
       
    71 static void MxCloseChannel(MixerChannel *mc)
       
    72 {
       
    73 	if (mc->flags & MX_AUTOFREE) free(mc->memory);
       
    74 	mc->active = false;
       
    75 	mc->memory = NULL;
       
    76 }
       
    77 
       
    78 void MxMixSamples(void *buffer, uint samples)
       
    79 {
       
    80 	MixerChannel *mc;
       
    81 
       
    82 	// Clear the buffer
       
    83 	memset(buffer, 0, sizeof(int16) * 2 * samples);
       
    84 
       
    85 	// Mix each channel
       
    86 	for (mc = _channels; mc != endof(_channels); mc++) {
       
    87 		if (mc->active) {
       
    88 			mix_int8_to_int16(mc, buffer, samples);
       
    89 			if (mc->samples_left == 0) MxCloseChannel(mc);
       
    90 		}
       
    91 	}
       
    92 }
       
    93 
       
    94 MixerChannel *MxAllocateChannel(void)
       
    95 {
       
    96 	MixerChannel *mc;
       
    97 	for (mc = _channels; mc != endof(_channels); mc++)
       
    98 		if (mc->memory == NULL) {
       
    99 			mc->active = false;
       
   100 			return mc;
       
   101 		}
       
   102 	return NULL;
       
   103 }
       
   104 
       
   105 void MxSetChannelRawSrc(MixerChannel *mc, int8 *mem, uint size, uint rate, uint flags)
       
   106 {
       
   107 	mc->memory = mem;
       
   108 	mc->flags = flags;
       
   109 	mc->frac_pos = 0;
       
   110 	mc->pos = 0;
       
   111 
       
   112 	mc->frac_speed = (rate << 16) / _play_rate;
       
   113 
       
   114 	// adjust the magnitude to prevent overflow
       
   115 	while (size & 0xFFFF0000) {
       
   116 		size >>= 1;
       
   117 		rate = (rate >> 1) + 1;
       
   118 	}
       
   119 
       
   120 	mc->samples_left = size * _play_rate / rate;
       
   121 }
       
   122 
       
   123 void MxSetChannelVolume(MixerChannel *mc, uint left, uint right)
       
   124 {
       
   125 	mc->volume_left = left;
       
   126 	mc->volume_right = right;
       
   127 }
       
   128 
       
   129 
       
   130 void MxActivateChannel(MixerChannel* mc)
       
   131 {
       
   132 	mc->active = true;
       
   133 }
       
   134 
       
   135 
       
   136 bool MxInitialize(uint rate)
       
   137 {
       
   138 	_play_rate = rate;
       
   139 	return true;
       
   140 }