/// <summary> /// Processes the change of the EAR bit value /// </summary> /// <param name="fromTape"> /// False: EAR bit comes from an OUT instruction, /// True: EAR bit comes from tape /// </param> /// <param name="earBit">EAR bit value</param> public void ProcessEarBitValue(bool fromTape, bool earBit) { if (!fromTape && _useTapeMode) { // --- The EAR bit comes from and OUT instruction, but now we're in tape mode return; } if (earBit == LastEarBit) { // --- The earbit has not changed return; } LastEarBit = earBit; var currentHostTact = HostVm.CurrentFrameTact; var currentTact = currentHostTact <= _frameTacts ? currentHostTact : _frameTacts; var length = currentTact - LastPulseTact; // --- If the first tact changes the pulse, we do // --- not add it if (length > 0) { Pulses.Add(new EarBitPulse { EarBit = !earBit, Lenght = length }); } LastPulseTact = currentTact; }
/// <summary> /// Frame is completed /// </summary> public void EndFrame() { // store the last pulse information if (LastPulseTState <= _tStatesPerFrame - 1) { Pulse p = new Pulse { State = LastPulse, Length = _tStatesPerFrame - LastPulseTState }; Pulses.Add(p); } // create the sample array var firstSampleOffset = _frameStart % TStatesPerSample == 0 ? 0 : TStatesPerSample - (_frameStart + TStatesPerSample) % TStatesPerSample; var samplesInFrame = (_tStatesPerFrame - firstSampleOffset - 1) / TStatesPerSample + 1; var samples = new short[samplesInFrame]; // convert pulses to samples var sampleIndex = 0; var currentEnd = _frameStart; foreach (var pulse in Pulses) { var firstSample = currentEnd % TStatesPerSample == 0 ? currentEnd : currentEnd + TStatesPerSample - currentEnd % TStatesPerSample; for (var i = firstSample; i < currentEnd + pulse.Length; i += TStatesPerSample) { samples[sampleIndex++] = pulse.State ? (short)(_volume) : (short)0; } currentEnd += pulse.Length; } // fill the _sampleBuffer for ISoundProvider soundBufferContains = (int)samplesInFrame; if (soundBuffer.Length != soundBufferContains) { soundBuffer = new short[soundBufferContains]; } samples.CopyTo(soundBuffer, 0); _frameStart += _tStatesPerFrame; }
/// <summary> /// When the pulse value changes it is processed here /// </summary> /// <param name="pulse"></param> public void ProcessPulseValue(bool pulse) { if (!_machine._renderSound) { return; } if (pulse == LastPulse) { // no change detected return; } // set the lastpulse LastPulse = pulse; // get where we are in the frame var currentULACycle = _machine.CurrentFrameCycle; var currentBuzzerCycle = currentULACycle <= _tStatesPerFrame ? currentULACycle : _tStatesPerFrame; var length = currentBuzzerCycle - LastPulseTState; if (length == 0) { // the first T-State has changed the pulse // do not add it } else if (length > 0) { // add the pulse Pulse p = new Pulse { State = !pulse, Length = length }; Pulses.Add(p); } // set the last pulse tstate LastPulseTState = currentBuzzerCycle; }
/// <summary> /// Allow the device to react to the completion of a frame /// </summary> public void OnFrameCompleted() { if (LastPulseTact <= _frameTacts - 1) { // --- We have to store the last pulse information Pulses.Add(new EarBitPulse { EarBit = LastEarBit, Lenght = _frameTacts - LastPulseTact }); } // --- Create the array for the samples var firstSampleOffset = _frameBegins % _tactsPerSample == 0 ? 0 : _tactsPerSample - (_frameBegins + _tactsPerSample) % _tactsPerSample; var samplesInFrame = (_frameTacts - firstSampleOffset - 1) / _tactsPerSample + 1; var samples = new float[samplesInFrame]; // --- Convert pulses to samples var sampleIndex = 0; var currentEnd = _frameBegins; foreach (var pulse in Pulses) { var firstSample = currentEnd % _tactsPerSample == 0 ? currentEnd : currentEnd + _tactsPerSample - currentEnd % _tactsPerSample; for (var i = firstSample; i < currentEnd + pulse.Lenght; i += _tactsPerSample) { samples[sampleIndex++] = pulse.EarBit ? 1.0F : 0.0F; } currentEnd += pulse.Lenght; } _beeperProvider?.AddSoundFrame(samples); _frameBegins += _frameTacts; }