Skip to content

Commit

Permalink
Completed support for the keyboard beeper. The Star can now beep at you.
Browse files Browse the repository at this point in the history
  • Loading branch information
jdersch committed May 26, 2019
1 parent e1a2b54 commit 0a6187a
Show file tree
Hide file tree
Showing 8 changed files with 147 additions and 111 deletions.
5 changes: 5 additions & 0 deletions D/Conversion.cs
Original file line number Diff line number Diff line change
Expand Up @@ -45,5 +45,10 @@ public static class Conversion
/// Conversion from microseconds to nanoseconds
/// </summary>
public static readonly ulong UsecToNsec = 1000;

/// <summary>
/// Conversion from microseconds to seconds
/// </summary>
public static readonly double UsecToSec = 0.000001;
}
}
2 changes: 1 addition & 1 deletion D/Darkstar.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -122,7 +122,7 @@
<Compile Include="Display\DisplayController.cs" />
<Compile Include="Ethernet\HostEthernet.cs" />
<Compile Include="Ethernet\IPacketInterface.cs" />
<Compile Include="IOP\Tone.cs" />
<Compile Include="IOP\Beeper.cs" />
<Compile Include="Properties\Settings.Designer.cs">
<AutoGen>True</AutoGen>
<DesignTimeSharedInput>True</DesignTimeSharedInput>
Expand Down
109 changes: 109 additions & 0 deletions D/IOP/Beeper.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
using D.Logging;
using SDL2;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading.Tasks;

namespace D.IOP
{
/// <summary>
/// Implements the tone generator used to generate simple beeps.
/// This is driven by an i8253 programmable interval timer.
/// </summary>
public class Beeper
{
public Beeper()
{
Reset();
}

public void Reset()
{
_lsb = 0;
_loadLSB = true;
_frequency = 0.0;
_enabled = false;
_sampleOn = false;
_periodInSamples = 0;

_sampleBuffer = new byte[0x10000];
}

public void LoadPeriod(byte value)
{
if (_loadLSB)
{
_lsb = value;
}
else
{
// "The period (in usec*1.8432) will be in the range ~29..65535."
double period = ((value << 8) | _lsb) / 1.8432;

// The above is in usec; convert to seconds:
period = period * Conversion.UsecToSec;

// Invert to get the frequency in Hz:
_frequency = 1.0 / period;

if (Log.Enabled) Log.Write(LogComponent.Beeper, "Tone frequency set to {0}", _frequency);

// And find out the length in samples at 44.1Khz.
_periodInSamples = 44100.0 / _frequency;
}

_loadLSB = !_loadLSB;
}

public void EnableTone()
{
if (Log.Enabled) Log.Write(LogComponent.Beeper, "Tone enabled.", _frequency);
_enabled = true;
}

public void DisableTone()
{
if (Log.Enabled && _enabled) Log.Write(LogComponent.Beeper, "Tone disabled.", _frequency);
_enabled = false;
}

public void AudioCallback(IntPtr userData, IntPtr stream, int length)
{
if (_enabled)
{
for (int i = 0; i < length; i++)
{
_position++;

if (_position > _periodInSamples)
{
_position -= _periodInSamples;
_sampleOn = !_sampleOn;
}

_sampleBuffer[i] = (byte)(_enabled ? (_sampleOn ? 0x3f : 0x00) : 0x00);
}
}
else
{
Array.Clear(_sampleBuffer, 0, length);
}

Marshal.Copy(_sampleBuffer, 0, stream, length);
}

private byte[] _sampleBuffer;

private bool _loadLSB;
private byte _lsb;

private double _frequency;
private bool _enabled;
private double _position;
private double _periodInSamples;
private bool _sampleOn;
}
}
8 changes: 4 additions & 4 deletions D/IOP/IOProcessor.cs
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ public IOProcessor(DSystem system)
_floppyController = new FloppyController(_floppyDrive, _system);
_dma = new DMAController(this);
_tty = new Printer();
_tone = new Tone();
_beeper = new Beeper();

//
// Register DMA devices with controller
Expand Down Expand Up @@ -143,9 +143,9 @@ public Printer Printer
get { return _tty; }
}

public Tone Tone
public Beeper Beeper
{
get { return _tone; }
get { return _beeper; }
}

private i8085 _cpu;
Expand All @@ -161,7 +161,7 @@ public Tone Tone
private Keyboard _keyboard;
private Mouse _mouse;
private Printer _tty;
private Tone _tone;
private Beeper _beeper;
private DSystem _system;

//
Expand Down
6 changes: 3 additions & 3 deletions D/IOP/MiscIO.cs
Original file line number Diff line number Diff line change
Expand Up @@ -120,7 +120,7 @@ public void WritePort(int port, byte value)
// i8253 Timer channel #1 - used to set the Keyboard bell (tone) frequency.
// This is a 16-bit value loaded one byte at a time, LSB first.
// Send the word off to the tone generator.
_iop.Tone.LoadInterval(value);
_iop.Beeper.LoadPeriod(value);
break;

case 0x8f:
Expand Down Expand Up @@ -180,11 +180,11 @@ public void WritePort(int port, byte value)

if ((value & 0x20) != 0)
{
_iop.Tone.EnableTone();
_iop.Beeper.EnableTone();
}
else
{
_iop.Tone.DisableTone();
_iop.Beeper.DisableTone();
}

if ((value & 0x10) != 0)
Expand Down
91 changes: 0 additions & 91 deletions D/IOP/Tone.cs

This file was deleted.

8 changes: 4 additions & 4 deletions D/Logging/Log.cs
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,7 @@ public enum LogComponent
EthernetPacket = 0x10000000,

// Keyboard tone
Tone = 0x20000000,
Beeper = 0x20000000,

// Configuration
Configuration = 0x40000000,
Expand Down Expand Up @@ -111,9 +111,9 @@ public static class Log
{
static Log()
{
Enabled = true;
_components = LogComponent.Tone | LogComponent.IOPPrinter;
_type = LogType.All;
Enabled = false;
_components = LogComponent.None;
_type = LogType.None;
_logIndex = 0;
}

Expand Down
29 changes: 21 additions & 8 deletions D/UI/DWindow-IO.cs
Original file line number Diff line number Diff line change
Expand Up @@ -974,6 +974,8 @@ private void InitializeSDL()
{
int retVal;

SDL.SDL_SetHint("SDL_WINDOWS_DISABLE_THREAD_NAMING", "1");

// Get SDL humming
if ((retVal = SDL.SDL_Init(SDL.SDL_INIT_EVERYTHING)) < 0)
{
Expand Down Expand Up @@ -1030,25 +1032,28 @@ private void InitializeSDL()
_renderEvent = new SDL.SDL_Event();
_renderEvent.type = (SDL.SDL_EventType)_renderEventType;



//
// Initialize SDL Audio:
// I'd prefer to do this in the Beeper class but there's some undocumented
// dependency on having an active SDL window, so we do it here to keep
// things simple.
//
SDL.SDL_AudioSpec desired = new SDL.SDL_AudioSpec();
SDL.SDL_AudioSpec obtained = new SDL.SDL_AudioSpec();

_audioCallback = _system.IOP.Beeper.AudioCallback;

desired.freq = 44100;
desired.format = SDL.AUDIO_U8;
desired.channels = 1;
desired.callback = _system.IOP.Tone.AudioCallback;
desired.samples = 1;
desired.callback = _audioCallback;
desired.samples = 1024;

uint deviceId = SDL.SDL_OpenAudioDevice(null, 0, ref desired, out obtained, 0);


SDL.SDL_PauseAudioDevice(deviceId, 0);

if (Log.Enabled) Log.Write(LogComponent.Tone, "SDL Audio initialized, device id {0}", deviceId);


if (Log.Enabled) Log.Write(LogComponent.Beeper, "SDL Audio initialized, device id {0}", deviceId);
}

private void CreateDisplayTexture(bool filter)
Expand Down Expand Up @@ -1206,5 +1211,13 @@ private void ToggleFullScreen(bool fullScreen)
// Rendering textures
private IntPtr _displayTexture = IntPtr.Zero;
private ReaderWriterLockSlim _textureLock;

//
// Local reference for the SDL Audio callback:
// SDL-CS doesn't hold this reference which causes
// problems when the GC runs. We keep this reference for as long
// as the Display Window is active.
//
private SDL.SDL_AudioCallback _audioCallback;
}
}

0 comments on commit 0a6187a

Please sign in to comment.