mixer.c
changeset 1496 15d859a626e8
child 1497 4fc9f620d3e0
equal deleted inserted replaced
1495:a9e4e2b78877 1496:15d859a626e8
       
     1 #include "stdafx.h"
       
     2 #include "ttd.h"
       
     3 #include "mixer.h"
       
     4 
       
     5 struct MixerChannel {
       
     6 	// Mixer
       
     7 	Mixer *mx;
       
     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 struct Mixer {
       
    27 	uint32 play_rate;
       
    28 	MixerChannel channels[8];
       
    29 };
       
    30 
       
    31 
       
    32 static void mix_int8_to_int16(MixerChannel *sc, int16 *buffer, uint samples)
       
    33 {
       
    34 	int8 *b;
       
    35 	uint32 frac_pos;
       
    36 	uint32 frac_speed;
       
    37 	uint volume_left;
       
    38 	uint volume_right;
       
    39 
       
    40 	if (samples > sc->samples_left) samples = sc->samples_left;
       
    41 	sc->samples_left -= samples;
       
    42 	assert(samples > 0);
       
    43 
       
    44 	b = sc->memory + sc->pos;
       
    45 	frac_pos = sc->frac_pos;
       
    46 	frac_speed = sc->frac_speed;
       
    47 	volume_left = sc->volume_left;
       
    48 	volume_right = sc->volume_right;
       
    49 
       
    50 	if (frac_speed == 0x10000) {
       
    51 		// Special case when frac_speed is 0x10000
       
    52 		do {
       
    53 			buffer[0] += *b * volume_left >> 8;
       
    54 			buffer[1] += *b * volume_right >> 8;
       
    55 			b++;
       
    56 			buffer += 2;
       
    57 		} while (--samples > 0);
       
    58 	} else {
       
    59 		do {
       
    60 			buffer[0] += *b * volume_left >> 8;
       
    61 			buffer[1] += *b * volume_right >> 8;
       
    62 			buffer += 2;
       
    63 			frac_pos += frac_speed;
       
    64 			b += frac_pos >> 16;
       
    65 			frac_pos &= 0xffff;
       
    66 		} while (--samples > 0);
       
    67 	}
       
    68 
       
    69 	sc->frac_pos = frac_pos;
       
    70 	sc->pos = b - sc->memory;
       
    71 }
       
    72 
       
    73 static void MxCloseChannel(MixerChannel *mc)
       
    74 {
       
    75 	if (mc->flags & MX_AUTOFREE) free(mc->memory);
       
    76 	mc->memory = NULL;
       
    77 	mc->active = false;
       
    78 }
       
    79 
       
    80 void MxMixSamples(Mixer *mx, void *buffer, uint samples)
       
    81 {
       
    82 	MixerChannel *mc;
       
    83 
       
    84 	// Clear the buffer
       
    85 	memset(buffer, 0, sizeof(int16) * 2 * samples);
       
    86 
       
    87 	// Mix each channel
       
    88 	for (mc = mx->channels; mc != endof(mx->channels); mc++) {
       
    89 		if (mc->active) {
       
    90 			mix_int8_to_int16(mc, buffer, samples);
       
    91 			if (mc->samples_left == 0) MxCloseChannel(mc);
       
    92 		}
       
    93 	}
       
    94 
       
    95 	#if 0
       
    96 	{
       
    97 		static FILE *out = NULL;
       
    98 		if (out == NULL)
       
    99 			out = fopen("d:\\dump.raw", "wb");
       
   100 		fwrite(buffer, samples * 4, 1, out);
       
   101 	}
       
   102 	#endif
       
   103 }
       
   104 
       
   105 MixerChannel *MxAllocateChannel(Mixer *mx)
       
   106 {
       
   107 	MixerChannel *mc;
       
   108 	for (mc = mx->channels; mc != endof(mx->channels); mc++)
       
   109 		if (mc->memory == NULL) {
       
   110 			mc->active = false;
       
   111 			mc->mx = mx;
       
   112 			return mc;
       
   113 		}
       
   114 	return NULL;
       
   115 }
       
   116 
       
   117 void MxSetChannelRawSrc(MixerChannel *mc, int8 *mem, uint size, uint rate, uint flags)
       
   118 {
       
   119 	mc->memory = mem;
       
   120 	mc->flags = flags;
       
   121 	mc->frac_pos = 0;
       
   122 	mc->pos = 0;
       
   123 
       
   124 	mc->frac_speed = (rate << 16) / mc->mx->play_rate;
       
   125 
       
   126 	// adjust the magnitude to prevent overflow
       
   127 	while (size & 0xFFFF0000) {
       
   128 		size >>= 1;
       
   129 		rate = (rate >> 1) + 1;
       
   130 	}
       
   131 
       
   132 	mc->samples_left = size * mc->mx->play_rate / rate;
       
   133 }
       
   134 
       
   135 void MxSetChannelVolume(MixerChannel *mc, uint left, uint right)
       
   136 {
       
   137 	mc->volume_left = left;
       
   138 	mc->volume_right = right;
       
   139 }
       
   140 
       
   141 
       
   142 void MxActivate(MixerChannel* mc)
       
   143 {
       
   144 	mc->active = true;
       
   145 }
       
   146 
       
   147 
       
   148 bool MxInitialize(uint rate)
       
   149 {
       
   150 	static Mixer mx;
       
   151 	_mixer = &mx;
       
   152 	mx.play_rate = rate;
       
   153 	return true;
       
   154 }