1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152
|
//Simple macros for checking samples!
//Precalcs handling!
#define C_SAMPLEPOS(channel) (channel->sound.position)
#define C_BUFFERSIZE(channel) (channel->sound.numsamples)
#define C_BUFFERINC(channel) (channel->bufferinc)
//Use precalculated sample positions!
//#define C_SAMPLERATE(channel,position) (convert_samplerate[soundchannels[(channel)].samplerate][(position)])
#define C_SAMPLERATE(channel,position) (uint_32)(channel->convert_samplerate*((float)(position)))
#define C_STEREO(channel) (channel->stereo)
#define C_GETSAMPLEPOS(channel,rchannel,time) (samplepos[C_STEREO(channel)][(((word)time)<<1)|(rchannel)])
#define C_VOLUMEPERCENT(channel) (channel->volume_percent)
#define C_SAMPLE(channel,samplepos) getsample(channel,samplepos)
static OPTINLINE void mixchannel(playing_p currentchannel, int_32 *result_l, int_32 *result_r) //Mixes the channels with each other at a specific time!
{
//Process multichannel!
uint_32 relsample; //Current channel and relative sample!
//Channel specific data
uint_32 currentpos, bufferinc; //Current sample pos, buffered samples!
//First, initialise our variables!
#ifdef DEBUG_SOUNDBUFFER
buffering = 0; //initialise buffering flag!
#endif
//First step: buffering if needed and keep our buffer!
currentpos = C_SAMPLEPOS(currentchannel); //Load the current position!
if (currentchannel->init) //First sample to run?
{
currentpos = 0; //Reset samplepos!
relsample = 0; //Reset relative sample!
#ifdef DEBUG_SOUNDBUFFER
dolog("soundservice","Initialising sound buffer...");
dolog("soundservice","Buffering %i @ 0/%i samples; extra data: %p; name: %s",n,C_BUFFERSIZE(currentchannel),currentchannel->extradata,currentchannel->name);
#endif
//Buffer and update buffer position!
currentchannel->bufferflags = currentchannel->soundhandler(currentchannel->sound.samples,C_BUFFERSIZE(currentchannel),C_STEREO(currentchannel),currentchannel->extradata); // Request next sample for this channel, also give our channel extra information!
currentchannel->init = 0; //Not initialised!
}
else //Not initialised? We're a running channel!
{
#ifdef DEBUG_SOUNDBUFFER
byte buffering = 0; //We're buffered?
#endif
bufferinc = C_BUFFERINC(currentchannel); //Load buffer increase rate!
relsample = C_SAMPLERATE(currentchannel,currentpos); //Get the sample position of the destination samplerate!
rebuffer: //Rebuffer check!
if (relsample>=C_BUFFERSIZE(currentchannel)) //Expired, we've reached the end of the buffer (sample overflow)?
{
#ifdef DEBUG_SOUNDBUFFER
buffering = 1; //We're buffering!
dolog("soundservice","Buffering %i @ %i/%i samples; extra data: %p; name: %s",n,relsample,C_BUFFERSIZE(currentchannel),currentchannel->extradata,currentchannel->name);
#endif
//Buffer and update buffer position!
currentchannel->bufferflags = currentchannel->soundhandler(currentchannel->sound.samples,C_BUFFERSIZE(currentchannel),C_STEREO(currentchannel),currentchannel->extradata); // Request next sample for this channel, also give our channel extra information!
currentpos -= bufferinc; //Reset position in the next frame!
relsample = C_SAMPLERATE(currentchannel,currentpos); //Get the sample rate for the new buffer!
goto rebuffer; //Rebuffer if needed!
} //Don't buffer!
#ifdef DEBUG_SOUNDBUFFER
if (buffering) //We were buffering?
{
buffering = 0;
dolog("soundservice","Buffer ready. Mixing...");
}
#endif
}
//Second step: Process the buffered sound itself!
if (currentchannel->bufferflags&1) //Do we even got something buffered?
{
float volume = C_VOLUMEPERCENT(currentchannel); //Retrieve the current volume!
int_32 sample_l = C_SAMPLE(currentchannel,C_GETSAMPLEPOS(currentchannel,0,relsample)); //The composed sample, based on the relative position!
int_32 sample_r = C_SAMPLE(currentchannel,C_GETSAMPLEPOS(currentchannel,1,relsample)); //The composed sample, based on the relative position!
//Apply the channel volume!
sample_l *= volume;
sample_r *= volume;
//Now we have the correct left and right channel data on our native samplerate.
//Next, add the data to the mixer!
*result_l += sample_l; //Mix the channels equally together based on volume!
*result_r += sample_r; //See above!
} //Mix!
//Finish up: update the values to be updated!
++currentpos; //Next position on each channel!
C_SAMPLEPOS(currentchannel) = currentpos; //Store the current position for next usage!
}
int_32 mixedsamples[SAMPLESIZE*2]; //All mixed samples buffer!
static OPTINLINE void mixaudio(sample_stereo_p buffer, uint_32 length) //Mix audio channels to buffer!
{
if (!length) return; //Abort without length!
//Current data numbers
uint_32 currentsample;
uint_32 channelsleft = soundchannels_used; //The ammount of channels to mix!
//Active data
playing_p activechannel; //Current channel!
int_32 *firstactivesample;
int_32 *activesample;
memset(&mixedsamples,0,sizeof(mixedsamples)); //Init mixed samples, stereo!
if (channelsleft)
{
activechannel = &soundchannels[0]; //Lookup the first channel!
for (;;) //Mix the next channel!
{
if (activechannel->soundhandler) //Active?
{
if (activechannel->samplerate &&
memprotect(activechannel->sound.samples,activechannel->sound.length,"SW_Samples")) //Allocated all neccesary channel data?
{
currentsample = 0;
activesample = &mixedsamples[0]; //Init active sample to the first sample!
for (;currentsample<length;) //Process all samples!
{
firstactivesample = activesample; //First channel sample!
++activesample; //Next sample!
mixchannel(activechannel,firstactivesample,activesample); //L&R channel!
++currentsample; //Next sample!
++activesample; //Next sample in our buffer!
}
}
}
if (!--channelsleft) break; //Stop when no channels left!
++activechannel; //Next channel!
}
} //Got channels?
//Process all generated samples to output!
currentsample = 0; //Init sample!
int_32 result_l, result_r; //Sample buffer!
activesample = &mixedsamples[0]; //Initialise the mixed samples position!
for (;;)
{
result_l = *activesample; //L channel!
++activesample; //Next sample!
result_r = *activesample; //R channel!
++activesample; //Next sample!
if (result_l>SHRT_MAX) result_l = SHRT_MAX;
if (result_l<SHRT_MIN) result_l = SHRT_MIN;
if (result_r>SHRT_MAX) result_r = SHRT_MAX;
if (result_r<SHRT_MIN) result_r = SHRT_MIN;
buffer->l = (sample_t)result_l; //Left channel!
buffer->r = (sample_t)result_r; //Right channel!
if (++currentsample>length) break; //Finished!
++buffer; //Next sample in the result!
}
}
|