in doom_py/src/vizdoom/src/oplsynth/dosbox/opl.cpp [914:1423]
void DBOPL::Update(float* sndptr, int numsamples) {
Bits i, endsamples;
op_type* cptr;
float outbufl[BLOCKBUF_SIZE];
#if defined(OPLTYPE_IS_OPL3)
// second output buffer (right channel for opl3 stereo)
float outbufr[BLOCKBUF_SIZE];
#endif
// vibrato/tremolo lookup tables (global, to possibly be used by all operators)
Bit32s vib_lut[BLOCKBUF_SIZE];
Bit32s trem_lut[BLOCKBUF_SIZE];
Bits samples_to_process = numsamples;
for (Bits cursmp=0; cursmp<samples_to_process; cursmp+=endsamples) {
endsamples = samples_to_process-cursmp;
if (endsamples>BLOCKBUF_SIZE) endsamples = BLOCKBUF_SIZE;
memset((void*)&outbufl,0,endsamples*sizeof(Bit32s));
#if defined(OPLTYPE_IS_OPL3)
// clear second output buffer (opl3 stereo)
if (adlibreg[0x105]&1) memset((void*)&outbufr,0,endsamples*sizeof(Bit32s));
#endif
// calculate vibrato/tremolo lookup tables
Bit32s vib_tshift = ((adlibreg[ARC_PERC_MODE]&0x40)==0) ? 1 : 0; // 14cents/7cents switching
for (i=0;i<endsamples;i++) {
// cycle through vibrato table
vibtab_pos += vibtab_add;
if (vibtab_pos/FIXEDPT_LFO>=VIBTAB_SIZE) vibtab_pos-=VIBTAB_SIZE*FIXEDPT_LFO;
vib_lut[i] = vib_table[vibtab_pos/FIXEDPT_LFO]>>vib_tshift; // 14cents (14/100 of a semitone) or 7cents
// cycle through tremolo table
tremtab_pos += tremtab_add;
if (tremtab_pos/FIXEDPT_LFO>=TREMTAB_SIZE) tremtab_pos-=TREMTAB_SIZE*FIXEDPT_LFO;
if (adlibreg[ARC_PERC_MODE]&0x80) trem_lut[i] = trem_table[tremtab_pos/FIXEDPT_LFO];
else trem_lut[i] = trem_table[TREMTAB_SIZE+tremtab_pos/FIXEDPT_LFO];
}
if (adlibreg[ARC_PERC_MODE]&0x20) {
//BassDrum
cptr = &op[6];
if (adlibreg[ARC_FEEDBACK+6]&1) {
// additive synthesis
if (cptr[9].op_state != OF_TYPE_OFF) {
if (cptr[9].vibrato) {
vibval1 = vibval_var1;
for (i=0;i<endsamples;i++)
vibval1[i] = (Bit32s)((vib_lut[i]*cptr[9].freq_high/8)*FIXEDPT*VIBFAC);
} else vibval1 = vibval_const;
if (cptr[9].tremolo) tremval1 = trem_lut; // tremolo enabled, use table
else tremval1 = tremval_const;
// calculate channel output
for (i=0;i<endsamples;i++) {
operator_advance(&cptr[9],vibval1[i]);
opfuncs[cptr[9].op_state](&cptr[9]);
operator_output(&cptr[9],0,tremval1[i]);
Bit32s chanval = cptr[9].cval*2;
CHANVAL_OUT
}
}
} else {
// frequency modulation
if ((cptr[9].op_state != OF_TYPE_OFF) || (cptr[0].op_state != OF_TYPE_OFF)) {
if ((cptr[0].vibrato) && (cptr[0].op_state != OF_TYPE_OFF)) {
vibval1 = vibval_var1;
for (i=0;i<endsamples;i++)
vibval1[i] = (Bit32s)((vib_lut[i]*cptr[0].freq_high/8)*FIXEDPT*VIBFAC);
} else vibval1 = vibval_const;
if ((cptr[9].vibrato) && (cptr[9].op_state != OF_TYPE_OFF)) {
vibval2 = vibval_var2;
for (i=0;i<endsamples;i++)
vibval2[i] = (Bit32s)((vib_lut[i]*cptr[9].freq_high/8)*FIXEDPT*VIBFAC);
} else vibval2 = vibval_const;
if (cptr[0].tremolo) tremval1 = trem_lut; // tremolo enabled, use table
else tremval1 = tremval_const;
if (cptr[9].tremolo) tremval2 = trem_lut; // tremolo enabled, use table
else tremval2 = tremval_const;
// calculate channel output
for (i=0;i<endsamples;i++) {
operator_advance(&cptr[0],vibval1[i]);
opfuncs[cptr[0].op_state](&cptr[0]);
operator_output(&cptr[0],(cptr[0].lastcval+cptr[0].cval)*cptr[0].mfbi/2,tremval1[i]);
operator_advance(&cptr[9],vibval2[i]);
opfuncs[cptr[9].op_state](&cptr[9]);
operator_output(&cptr[9],cptr[0].cval*FIXEDPT,tremval2[i]);
Bit32s chanval = cptr[9].cval*2;
CHANVAL_OUT
}
}
}
//TomTom (j=8)
if (op[8].op_state != OF_TYPE_OFF) {
cptr = &op[8];
if (cptr[0].vibrato) {
vibval3 = vibval_var1;
for (i=0;i<endsamples;i++)
vibval3[i] = (Bit32s)((vib_lut[i]*cptr[0].freq_high/8)*FIXEDPT*VIBFAC);
} else vibval3 = vibval_const;
if (cptr[0].tremolo) tremval3 = trem_lut; // tremolo enabled, use table
else tremval3 = tremval_const;
// calculate channel output
for (i=0;i<endsamples;i++) {
operator_advance(&cptr[0],vibval3[i]);
opfuncs[cptr[0].op_state](&cptr[0]); //TomTom
operator_output(&cptr[0],0,tremval3[i]);
Bit32s chanval = cptr[0].cval*2;
CHANVAL_OUT
}
}
//Snare/Hihat (j=7), Cymbal (j=8)
if ((op[7].op_state != OF_TYPE_OFF) || (op[16].op_state != OF_TYPE_OFF) ||
(op[17].op_state != OF_TYPE_OFF)) {
cptr = &op[7];
if ((cptr[0].vibrato) && (cptr[0].op_state != OF_TYPE_OFF)) {
vibval1 = vibval_var1;
for (i=0;i<endsamples;i++)
vibval1[i] = (Bit32s)((vib_lut[i]*cptr[0].freq_high/8)*FIXEDPT*VIBFAC);
} else vibval1 = vibval_const;
if ((cptr[9].vibrato) && (cptr[9].op_state == OF_TYPE_OFF)) {
vibval2 = vibval_var2;
for (i=0;i<endsamples;i++)
vibval2[i] = (Bit32s)((vib_lut[i]*cptr[9].freq_high/8)*FIXEDPT*VIBFAC);
} else vibval2 = vibval_const;
if (cptr[0].tremolo) tremval1 = trem_lut; // tremolo enabled, use table
else tremval1 = tremval_const;
if (cptr[9].tremolo) tremval2 = trem_lut; // tremolo enabled, use table
else tremval2 = tremval_const;
cptr = &op[8];
if ((cptr[9].vibrato) && (cptr[9].op_state == OF_TYPE_OFF)) {
vibval4 = vibval_var2;
for (i=0;i<endsamples;i++)
vibval4[i] = (Bit32s)((vib_lut[i]*cptr[9].freq_high/8)*FIXEDPT*VIBFAC);
} else vibval4 = vibval_const;
if (cptr[9].tremolo) tremval4 = trem_lut; // tremolo enabled, use table
else tremval4 = tremval_const;
// calculate channel output
for (i=0;i<endsamples;i++) {
operator_advance_drums(&op[7],vibval1[i],&op[7+9],vibval2[i],&op[8+9],vibval4[i]);
opfuncs[op[7].op_state](&op[7]); //Hihat
operator_output(&op[7],0,tremval1[i]);
opfuncs[op[7+9].op_state](&op[7+9]); //Snare
operator_output(&op[7+9],0,tremval2[i]);
opfuncs[op[8+9].op_state](&op[8+9]); //Cymbal
operator_output(&op[8+9],0,tremval4[i]);
Bit32s chanval = (op[7].cval + op[7+9].cval + op[8+9].cval)*2;
CHANVAL_OUT
}
}
}
Bitu max_channel = NUM_CHANNELS;
#if defined(OPLTYPE_IS_OPL3)
if ((adlibreg[0x105]&1)==0) max_channel = NUM_CHANNELS/2;
#endif
for (Bits cur_ch=max_channel-1; cur_ch>=0; cur_ch--) {
// skip drum/percussion operators
if ((adlibreg[ARC_PERC_MODE]&0x20) && (cur_ch >= 6) && (cur_ch < 9)) continue;
Bitu k = cur_ch;
#if defined(OPLTYPE_IS_OPL3)
if (cur_ch < 9) {
cptr = &op[cur_ch];
} else {
cptr = &op[cur_ch+9]; // second set is operator18-operator35
k += (-9+256); // second set uses registers 0x100 onwards
}
// check if this operator is part of a 4-op
if ((adlibreg[0x105]&1) && cptr->is_4op_attached) continue;
#else
cptr = &op[cur_ch];
#endif
// check for FM/AM
if (adlibreg[ARC_FEEDBACK+k]&1) {
#if defined(OPLTYPE_IS_OPL3)
if ((adlibreg[0x105]&1) && cptr->is_4op) {
if (adlibreg[ARC_FEEDBACK+k+3]&1) {
// AM-AM-style synthesis (op1[fb] + (op2 * op3) + op4)
if (cptr[0].op_state != OF_TYPE_OFF) {
if (cptr[0].vibrato) {
vibval1 = vibval_var1;
for (i=0;i<endsamples;i++)
vibval1[i] = (Bit32s)((vib_lut[i]*cptr[0].freq_high/8)*FIXEDPT*VIBFAC);
} else vibval1 = vibval_const;
if (cptr[0].tremolo) tremval1 = trem_lut; // tremolo enabled, use table
else tremval1 = tremval_const;
// calculate channel output
for (i=0;i<endsamples;i++) {
operator_advance(&cptr[0],vibval1[i]);
opfuncs[cptr[0].op_state](&cptr[0]);
operator_output(&cptr[0],(cptr[0].lastcval+cptr[0].cval)*cptr[0].mfbi/2,tremval1[i]);
Bit32s chanval = cptr[0].cval;
CHANVAL_OUT
}
}
if ((cptr[3].op_state != OF_TYPE_OFF) || (cptr[9].op_state != OF_TYPE_OFF)) {
if ((cptr[9].vibrato) && (cptr[9].op_state != OF_TYPE_OFF)) {
vibval1 = vibval_var1;
for (i=0;i<endsamples;i++)
vibval1[i] = (Bit32s)((vib_lut[i]*cptr[9].freq_high/8)*FIXEDPT*VIBFAC);
} else vibval1 = vibval_const;
if (cptr[9].tremolo) tremval1 = trem_lut; // tremolo enabled, use table
else tremval1 = tremval_const;
if (cptr[3].tremolo) tremval2 = trem_lut; // tremolo enabled, use table
else tremval2 = tremval_const;
// calculate channel output
for (i=0;i<endsamples;i++) {
operator_advance(&cptr[9],vibval1[i]);
opfuncs[cptr[9].op_state](&cptr[9]);
operator_output(&cptr[9],0,tremval1[i]);
operator_advance(&cptr[3],0);
opfuncs[cptr[3].op_state](&cptr[3]);
operator_output(&cptr[3],cptr[9].cval*FIXEDPT,tremval2[i]);
Bit32s chanval = cptr[3].cval;
CHANVAL_OUT
}
}
if (cptr[3+9].op_state != OF_TYPE_OFF) {
if (cptr[3+9].tremolo) tremval1 = trem_lut; // tremolo enabled, use table
else tremval1 = tremval_const;
// calculate channel output
for (i=0;i<endsamples;i++) {
operator_advance(&cptr[3+9],0);
opfuncs[cptr[3+9].op_state](&cptr[3+9]);
operator_output(&cptr[3+9],0,tremval1[i]);
Bit32s chanval = cptr[3+9].cval;
CHANVAL_OUT
}
}
} else {
// AM-FM-style synthesis (op1[fb] + (op2 * op3 * op4))
if (cptr[0].op_state != OF_TYPE_OFF) {
if (cptr[0].vibrato) {
vibval1 = vibval_var1;
for (i=0;i<endsamples;i++)
vibval1[i] = (Bit32s)((vib_lut[i]*cptr[0].freq_high/8)*FIXEDPT*VIBFAC);
} else vibval1 = vibval_const;
if (cptr[0].tremolo) tremval1 = trem_lut; // tremolo enabled, use table
else tremval1 = tremval_const;
// calculate channel output
for (i=0;i<endsamples;i++) {
operator_advance(&cptr[0],vibval1[i]);
opfuncs[cptr[0].op_state](&cptr[0]);
operator_output(&cptr[0],(cptr[0].lastcval+cptr[0].cval)*cptr[0].mfbi/2,tremval1[i]);
Bit32s chanval = cptr[0].cval;
CHANVAL_OUT
}
}
if ((cptr[9].op_state != OF_TYPE_OFF) || (cptr[3].op_state != OF_TYPE_OFF) || (cptr[3+9].op_state != OF_TYPE_OFF)) {
if ((cptr[9].vibrato) && (cptr[9].op_state != OF_TYPE_OFF)) {
vibval1 = vibval_var1;
for (i=0;i<endsamples;i++)
vibval1[i] = (Bit32s)((vib_lut[i]*cptr[9].freq_high/8)*FIXEDPT*VIBFAC);
} else vibval1 = vibval_const;
if (cptr[9].tremolo) tremval1 = trem_lut; // tremolo enabled, use table
else tremval1 = tremval_const;
if (cptr[3].tremolo) tremval2 = trem_lut; // tremolo enabled, use table
else tremval2 = tremval_const;
if (cptr[3+9].tremolo) tremval3 = trem_lut; // tremolo enabled, use table
else tremval3 = tremval_const;
// calculate channel output
for (i=0;i<endsamples;i++) {
operator_advance(&cptr[9],vibval1[i]);
opfuncs[cptr[9].op_state](&cptr[9]);
operator_output(&cptr[9],0,tremval1[i]);
operator_advance(&cptr[3],0);
opfuncs[cptr[3].op_state](&cptr[3]);
operator_output(&cptr[3],cptr[9].cval*FIXEDPT,tremval2[i]);
operator_advance(&cptr[3+9],0);
opfuncs[cptr[3+9].op_state](&cptr[3+9]);
operator_output(&cptr[3+9],cptr[3].cval*FIXEDPT,tremval3[i]);
Bit32s chanval = cptr[3+9].cval;
CHANVAL_OUT
}
}
}
continue;
}
#endif
// 2op additive synthesis
if ((cptr[9].op_state == OF_TYPE_OFF) && (cptr[0].op_state == OF_TYPE_OFF)) continue;
if ((cptr[0].vibrato) && (cptr[0].op_state != OF_TYPE_OFF)) {
vibval1 = vibval_var1;
for (i=0;i<endsamples;i++)
vibval1[i] = (Bit32s)((vib_lut[i]*cptr[0].freq_high/8)*FIXEDPT*VIBFAC);
} else vibval1 = vibval_const;
if ((cptr[9].vibrato) && (cptr[9].op_state != OF_TYPE_OFF)) {
vibval2 = vibval_var2;
for (i=0;i<endsamples;i++)
vibval2[i] = (Bit32s)((vib_lut[i]*cptr[9].freq_high/8)*FIXEDPT*VIBFAC);
} else vibval2 = vibval_const;
if (cptr[0].tremolo) tremval1 = trem_lut; // tremolo enabled, use table
else tremval1 = tremval_const;
if (cptr[9].tremolo) tremval2 = trem_lut; // tremolo enabled, use table
else tremval2 = tremval_const;
// calculate channel output
for (i=0;i<endsamples;i++) {
// carrier1
operator_advance(&cptr[0],vibval1[i]);
opfuncs[cptr[0].op_state](&cptr[0]);
operator_output(&cptr[0],(cptr[0].lastcval+cptr[0].cval)*cptr[0].mfbi/2,tremval1[i]);
// carrier2
operator_advance(&cptr[9],vibval2[i]);
opfuncs[cptr[9].op_state](&cptr[9]);
operator_output(&cptr[9],0,tremval2[i]);
Bit32s chanval = cptr[9].cval + cptr[0].cval;
CHANVAL_OUT
}
} else {
#if defined(OPLTYPE_IS_OPL3)
if ((adlibreg[0x105]&1) && cptr->is_4op) {
if (adlibreg[ARC_FEEDBACK+k+3]&1) {
// FM-AM-style synthesis ((op1[fb] * op2) + (op3 * op4))
if ((cptr[0].op_state != OF_TYPE_OFF) || (cptr[9].op_state != OF_TYPE_OFF)) {
if ((cptr[0].vibrato) && (cptr[0].op_state != OF_TYPE_OFF)) {
vibval1 = vibval_var1;
for (i=0;i<endsamples;i++)
vibval1[i] = (Bit32s)((vib_lut[i]*cptr[0].freq_high/8)*FIXEDPT*VIBFAC);
} else vibval1 = vibval_const;
if ((cptr[9].vibrato) && (cptr[9].op_state != OF_TYPE_OFF)) {
vibval2 = vibval_var2;
for (i=0;i<endsamples;i++)
vibval2[i] = (Bit32s)((vib_lut[i]*cptr[9].freq_high/8)*FIXEDPT*VIBFAC);
} else vibval2 = vibval_const;
if (cptr[0].tremolo) tremval1 = trem_lut; // tremolo enabled, use table
else tremval1 = tremval_const;
if (cptr[9].tremolo) tremval2 = trem_lut; // tremolo enabled, use table
else tremval2 = tremval_const;
// calculate channel output
for (i=0;i<endsamples;i++) {
operator_advance(&cptr[0],vibval1[i]);
opfuncs[cptr[0].op_state](&cptr[0]);
operator_output(&cptr[0],(cptr[0].lastcval+cptr[0].cval)*cptr[0].mfbi/2,tremval1[i]);
operator_advance(&cptr[9],vibval2[i]);
opfuncs[cptr[9].op_state](&cptr[9]);
operator_output(&cptr[9],cptr[0].cval*FIXEDPT,tremval2[i]);
Bit32s chanval = cptr[9].cval;
CHANVAL_OUT
}
}
if ((cptr[3].op_state != OF_TYPE_OFF) || (cptr[3+9].op_state != OF_TYPE_OFF)) {
if (cptr[3].tremolo) tremval1 = trem_lut; // tremolo enabled, use table
else tremval1 = tremval_const;
if (cptr[3+9].tremolo) tremval2 = trem_lut; // tremolo enabled, use table
else tremval2 = tremval_const;
// calculate channel output
for (i=0;i<endsamples;i++) {
operator_advance(&cptr[3],0);
opfuncs[cptr[3].op_state](&cptr[3]);
operator_output(&cptr[3],0,tremval1[i]);
operator_advance(&cptr[3+9],0);
opfuncs[cptr[3+9].op_state](&cptr[3+9]);
operator_output(&cptr[3+9],cptr[3].cval*FIXEDPT,tremval2[i]);
Bit32s chanval = cptr[3+9].cval;
CHANVAL_OUT
}
}
} else {
// FM-FM-style synthesis (op1[fb] * op2 * op3 * op4)
if ((cptr[0].op_state != OF_TYPE_OFF) || (cptr[9].op_state != OF_TYPE_OFF) ||
(cptr[3].op_state != OF_TYPE_OFF) || (cptr[3+9].op_state != OF_TYPE_OFF)) {
if ((cptr[0].vibrato) && (cptr[0].op_state != OF_TYPE_OFF)) {
vibval1 = vibval_var1;
for (i=0;i<endsamples;i++)
vibval1[i] = (Bit32s)((vib_lut[i]*cptr[0].freq_high/8)*FIXEDPT*VIBFAC);
} else vibval1 = vibval_const;
if ((cptr[9].vibrato) && (cptr[9].op_state != OF_TYPE_OFF)) {
vibval2 = vibval_var2;
for (i=0;i<endsamples;i++)
vibval2[i] = (Bit32s)((vib_lut[i]*cptr[9].freq_high/8)*FIXEDPT*VIBFAC);
} else vibval2 = vibval_const;
if (cptr[0].tremolo) tremval1 = trem_lut; // tremolo enabled, use table
else tremval1 = tremval_const;
if (cptr[9].tremolo) tremval2 = trem_lut; // tremolo enabled, use table
else tremval2 = tremval_const;
if (cptr[3].tremolo) tremval3 = trem_lut; // tremolo enabled, use table
else tremval3 = tremval_const;
if (cptr[3+9].tremolo) tremval4 = trem_lut; // tremolo enabled, use table
else tremval4 = tremval_const;
// calculate channel output
for (i=0;i<endsamples;i++) {
operator_advance(&cptr[0],vibval1[i]);
opfuncs[cptr[0].op_state](&cptr[0]);
operator_output(&cptr[0],(cptr[0].lastcval+cptr[0].cval)*cptr[0].mfbi/2,tremval1[i]);
operator_advance(&cptr[9],vibval2[i]);
opfuncs[cptr[9].op_state](&cptr[9]);
operator_output(&cptr[9],cptr[0].cval*FIXEDPT,tremval2[i]);
operator_advance(&cptr[3],0);
opfuncs[cptr[3].op_state](&cptr[3]);
operator_output(&cptr[3],cptr[9].cval*FIXEDPT,tremval3[i]);
operator_advance(&cptr[3+9],0);
opfuncs[cptr[3+9].op_state](&cptr[3+9]);
operator_output(&cptr[3+9],cptr[3].cval*FIXEDPT,tremval4[i]);
Bit32s chanval = cptr[3+9].cval;
CHANVAL_OUT
}
}
}
continue;
}
#endif
// 2op frequency modulation
if ((cptr[9].op_state == OF_TYPE_OFF) && (cptr[0].op_state == OF_TYPE_OFF)) continue;
if ((cptr[0].vibrato) && (cptr[0].op_state != OF_TYPE_OFF)) {
vibval1 = vibval_var1;
for (i=0;i<endsamples;i++)
vibval1[i] = (Bit32s)((vib_lut[i]*cptr[0].freq_high/8)*FIXEDPT*VIBFAC);
} else vibval1 = vibval_const;
if ((cptr[9].vibrato) && (cptr[9].op_state != OF_TYPE_OFF)) {
vibval2 = vibval_var2;
for (i=0;i<endsamples;i++)
vibval2[i] = (Bit32s)((vib_lut[i]*cptr[9].freq_high/8)*FIXEDPT*VIBFAC);
} else vibval2 = vibval_const;
if (cptr[0].tremolo) tremval1 = trem_lut; // tremolo enabled, use table
else tremval1 = tremval_const;
if (cptr[9].tremolo) tremval2 = trem_lut; // tremolo enabled, use table
else tremval2 = tremval_const;
// calculate channel output
for (i=0;i<endsamples;i++) {
// modulator
operator_advance(&cptr[0],vibval1[i]);
opfuncs[cptr[0].op_state](&cptr[0]);
operator_output(&cptr[0],(cptr[0].lastcval+cptr[0].cval)*cptr[0].mfbi/2,tremval1[i]);
// carrier
operator_advance(&cptr[9],vibval2[i]);
opfuncs[cptr[9].op_state](&cptr[9]);
operator_output(&cptr[9],cptr[0].cval*FIXEDPT,tremval2[i]);
Bit32s chanval = cptr[9].cval;
CHANVAL_OUT
}
}
}
#if defined(OPLTYPE_IS_OPL3)
if (adlibreg[0x105]&1) {
// convert to float samples (stereo->stereo)
for (i=0;i<endsamples;i++) {
clipit16(outbufl[i],sndptr++);
clipit16(outbufr[i],sndptr++);
}
} else {
// convert to float samples (mono->stereo)
for (i=0;i<endsamples;i++) {
clipit16(outbufl[i],sndptr++);
clipit16(outbufl[i],sndptr++);
}
}
#else
// convert to float samples
for (i=0;i<endsamples;i++)
clipit16(outbufl[i],sndptr++);
#endif
}
}