static STREAM_UPDATE( s14001a_pcm_update ) { INT32 mix[48000]; //INT32 *mixp; S14001AChip *chip = (S14001AChip *)param; int i; memset(mix, 0, sizeof(mix)); //mixp = &mix[0]; for (i = 0; i < samples; i++) { s14001a_clock(chip); #ifdef ACCURATE_SQUEAL if (chip->audioout == ALTFLAG) // input from test pins -> output { shiftIntoFilter(chip, audiofilter(chip)); // shift over the previous outputs and stick in audioout. outputs[0][i] = audiofilter(chip)*chip->VSU1000_amp; } else // normal, dac-driven output { shiftIntoFilter(chip, ((((INT16)chip->audioout)-8)<<9)); // shift over the previous outputs and stick in audioout 4 times. note <<9 instead of <<10, to prevent clipping, and to simulate that the filtered output normally has a somewhat lower amplitude than the driven one. #endif outputs[0][i] = ((((INT16)chip->audioout)-8)<<10)*chip->VSU1000_amp; #ifdef ACCURATE_SQUEAL } #endif } }
void s14001a_device::sound_stream_update(sound_stream &stream, stream_sample_t **inputs, stream_sample_t **outputs, int samples) { int i; for (i = 0; i < samples; i++) { s14001a_clock(); #ifdef ACCURATE_SQUEAL if (m_audioout == ALTFLAG) // input from test pins -> output { shiftIntoFilter(chip, audiofilter(chip)); // shift over the previous outputs and stick in audioout. outputs[0][i] = audiofilter(chip)*m_VSU1000_amp; } else // normal, dac-driven output { shiftIntoFilter(chip, ((((INT16)m_audioout)-8)<<9)); // shift over the previous outputs and stick in audioout 4 times. note <<9 instead of <<10, to prevent clipping, and to simulate that the filtered output normally has a somewhat lower amplitude than the driven one. #endif outputs[0][i] = ((((INT16)m_audioout)-8)<<10)*m_VSU1000_amp; #ifdef ACCURATE_SQUEAL } #endif } }
void s14001a_clock(void) /* called once per clock */ { UINT8 CurDelta; // Current delta /* on even clocks, audio output is floating, /romen is low so rom data bus is driven, input is latched? * on odd clocks, audio output is driven, /romen is high, state machine 2 is clocked */ oddeven = !(oddeven); // invert the clock if (oddeven == 0) // even clock { audioout = audiofilter(); // function to handle output filtering by internal capacitance based on clock speed and such #ifdef PINMAME if (!machineState) audioout = SILENCE; #endif shiftIntoFilter(audioout); // shift over all the filter outputs and stick in audioout } else // odd clock { // fix dac output between samples. theoretically this might be unnecessary but it would require some messy logic in state 5 on the first sample load. if (GlobalSilenceState || LOCALSILENCESTATE) { DACOutput = SILENCE; OldDelta = 2; } audioout = (GlobalSilenceState || LOCALSILENCESTATE) ? SILENCE : DACOutput; // when either silence state is 1, output silence. #ifdef PINMAME if (!machineState) audioout = SILENCE; #endif shiftIntoFilter(audioout); // shift over all the filter outputs and stick in audioout switch(machineState) { case 0: // idle state nextstate = 0; break; case 1: // read starting syllable high byte from word table SyllableAddress = 0; // clear syllable address SyllableAddress |= s14001a_readmem(LatchedWord<<1)<<4; nextstate = resetState ? 1 : 2; break; case 2: // read starting syllable low byte from word table SyllableAddress |= s14001a_readmem((LatchedWord<<1)+1)>>4; nextstate = 3; break; case 3: // read starting phone address PhoneAddress = s14001a_readmem(SyllableAddress)<<4; nextstate = 4; break; case 4: // read playback parameters and prepare for play PlayParams = s14001a_readmem(SyllableAddress+1); GlobalSilenceState = SILENCEFLAG; // load phone silence flag LengthCounter = LENGTHCOUNT; // load length counter RepeatCounter = REPEATCOUNT; // load repeat counter OutputCounter = 0; // clear output counter and disable mirrored phoneme silence indirectly via LOCALSILENCESTATE PhoneOffset = 0; // set offset within phone to zero OldDelta = 0x2; // set old delta to 2 <- is this right? DACOutput = 0x88; // set DAC output to center/silence position (0x88) nextstate = 5; break; case 5: // Play phone forward, shift = 0 (also load) CurDelta = (s14001a_readmem((PhoneAddress)+PhoneOffset)&0xc0)>>6; // grab current delta from high 2 bits of high nybble DACOutput += DeltaTable[CurDelta][OldDelta]; // send data to forward delta table and add result to accumulator OldDelta = CurDelta; // Move current delta to old nextstate = 6; break; case 6: // Play phone forward, shift = 2 CurDelta = (s14001a_readmem((PhoneAddress)+PhoneOffset)&0x30)>>4; // grab current delta from low 2 bits of high nybble DACOutput += DeltaTable[CurDelta][OldDelta]; // send data to forward delta table and add result to accumulator OldDelta = CurDelta; // Move current delta to old nextstate = 7; break; case 7: // Play phone forward, shift = 4 CurDelta = (s14001a_readmem((PhoneAddress)+PhoneOffset)&0xc)>>2; // grab current delta from high 2 bits of low nybble DACOutput += DeltaTable[CurDelta][OldDelta]; // send data to forward delta table and add result to accumulator OldDelta = CurDelta; // Move current delta to old nextstate = 8; break; case 8: // Play phone forward, shift = 6 (increment address if needed) CurDelta = s14001a_readmem((PhoneAddress)+PhoneOffset)&0x3; // grab current delta from low 2 bits of low nybble DACOutput += DeltaTable[CurDelta][OldDelta]; // send data to forward delta table and add result to accumulator OldDelta = CurDelta; // Move current delta to old PhoneOffset++; // increment phone offset if (PhoneOffset == 0x8) // if we're now done this phone { /* call the PostPhoneme Function */ PostPhoneme(); } else { nextstate = 5; } break; case 9: // Play phone backward, shift = 6 (also load) CurDelta = (s14001a_readmem((PhoneAddress)+PhoneOffset)&0x3); // grab current delta from low 2 bits of low nybble if (laststate != 8) // ignore first (bogus) dac change in mirrored backwards mode. observations and the patent show this. { DACOutput -= DeltaTable[OldDelta][CurDelta]; // send data to forward delta table and subtract result from accumulator } OldDelta = CurDelta; // Move current delta to old nextstate = 10; break; case 10: // Play phone backward, shift = 4 CurDelta = (s14001a_readmem((PhoneAddress)+PhoneOffset)&0xc)>>2; // grab current delta from high 2 bits of low nybble DACOutput -= DeltaTable[OldDelta][CurDelta]; // send data to forward delta table and subtract result from accumulator OldDelta = CurDelta; // Move current delta to old nextstate = 11; break; case 11: // Play phone backward, shift = 2 CurDelta = (s14001a_readmem((PhoneAddress)+PhoneOffset)&0x30)>>4; // grab current delta from low 2 bits of high nybble DACOutput -= DeltaTable[OldDelta][CurDelta]; // send data to forward delta table and subtract result from accumulator OldDelta = CurDelta; // Move current delta to old nextstate = 12; break; case 12: // Play phone backward, shift = 0 (increment address if needed) CurDelta = (s14001a_readmem((PhoneAddress)+PhoneOffset)&0xc0)>>6; // grab current delta from high 2 bits of high nybble DACOutput -= DeltaTable[OldDelta][CurDelta]; // send data to forward delta table and subtract result from accumulator OldDelta = CurDelta; // Move current delta to old PhoneOffset--; // decrement phone offset if (PhoneOffset == 0xFF) // if we're now done this phone { /* call the PostPhoneme() function */ PostPhoneme(); } else { nextstate = 9; } break; case 13: // For those pedantic among us, consume an extra two clocks like the real chip does. nextstate = 0; break; } #ifdef DEBUGSTATE fprintf(stderr, "Machine state is now %d, was %d, PhoneOffset is %d\n", nextstate, machineState, PhoneOffset); #endif laststate = machineState; machineState = nextstate; } }