{ int i; DATATYPE *buf = (DATATYPE *)buffer; struct SN76496 *R = &sn[chip]; /* If the volume is 0, increase the counter */ for (i = 0;i < 4;i++) { if (R->Volume[i] == 0) { /* note that I do count += length, NOT count = length + 1. You might think */ /* it's the same since the volume is 0, but doing the latter could cause */ /* interferencies when the program is rapidly modulating the volume. */ if (R->Count[i] <= length*STEP) R->Count[i] += length*STEP; } } while (length > 0) { int vol[4]; unsigned int out; int left; DATATYPE tmp; /* vol[] keeps track of how long each square wave stays */ /* in the 1 position during the sample period. */ vol[0] = vol[1] = vol[2] = vol[3] = 0; for (i = 0;i < 3;i++) { if (R->Output[i]) vol[i] += R->Count[i]; R->Count[i] -= STEP; /* Period[i] is the half period of the square wave. Here, in each */ /* loop I add Period[i] twice, so that at the end of the loop the */ /* square wave is in the same status (0 or 1) it was at the start. */ /* vol[i] is also incremented by Period[i], since the wave has been 1 */ /* exactly half of the time, regardless of the initial position. */ /* If we exit the loop in the middle, Output[i] has to be inverted */ /* and vol[i] incremented only if the exit status of the square */ /* wave is 1. */ while (R->Count[i] <= 0) { R->Count[i] += R->Period[i]; if (R->Count[i] > 0) { R->Output[i] ^= 1; if (R->Output[i]) vol[i] += R->Period[i]; break; } R->Count[i] += R->Period[i]; vol[i] += R->Period[i]; } if (R->Output[i]) vol[i] -= R->Count[i]; } left = STEP; do { int nextevent; if (R->Count[3] < left) nextevent = R->Count[3]; else nextevent = left; if (R->Output[3]) vol[3] += R->Count[3]; R->Count[3] -= nextevent; if (R->Count[3] <= 0) { if (R->RNG & 1) R->RNG ^= R->NoiseFB; R->RNG >>= 1; R->Output[3] = R->RNG & 1; R->Count[3] += R->Period[3]; if (R->Output[3]) vol[3] += R->Period[3]; } if (R->Output[3]) vol[3] -= R->Count[3]; left -= nextevent; } while (left > 0); out = vol[0] * R->Volume[0] + vol[1] * R->Volume[1] + vol[2] * R->Volume[2] + vol[3] * R->Volume[3]; if (out > MAX_OUTPUT * STEP) out = MAX_OUTPUT * STEP; tmp = ((DATACONV(out) * 3) >> 3); /* Dave: a bit quieter */ /* Both channels */ *(buf++) = tmp; *(buf++) = tmp; length--; } }