139 lines
3.4 KiB
D
139 lines
3.4 KiB
D
/+
|
|
+ device/speaker.d
|
|
+
|
|
+ Copyright: 2007 Gerald Stocker
|
|
+
|
|
+ This file is part of twoapple-reboot.
|
|
+
|
|
+ twoapple-reboot is free software; you can redistribute it and/or modify
|
|
+ it under the terms of the GNU General Public License as published by
|
|
+ the Free Software Foundation; either version 2 of the License, or
|
|
+ (at your option) any later version.
|
|
+
|
|
+ twoapple-reboot is distributed in the hope that it will be useful,
|
|
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
+ GNU General Public License for more details.
|
|
+
|
|
+ You should have received a copy of the GNU General Public License
|
|
+ along with twoapple-reboot; if not, write to the Free Software
|
|
+ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
|
+/
|
|
|
|
module device.speaker;
|
|
|
|
import std.c.string;
|
|
|
|
import device.base;
|
|
import memory;
|
|
import timer;
|
|
|
|
class Speaker
|
|
{
|
|
bool muted;
|
|
Timer.Cycle cycle;
|
|
|
|
int sampleTicks;
|
|
ushort sample;
|
|
|
|
uint lastToggleTick;
|
|
bool toggled;
|
|
|
|
short[] mainBuffer;
|
|
short[] extraBuffer;
|
|
uint mainIndex, extraIndex;
|
|
|
|
this()
|
|
{
|
|
sample = 0x8000;
|
|
mainBuffer.length = 8192;
|
|
}
|
|
|
|
void setTiming(uint hertz, int sampleFreq, Timer.Cycle deviceCycle)
|
|
{
|
|
extraBuffer.length = sampleTicks = (hertz / sampleFreq);
|
|
cycle = deviceCycle;
|
|
}
|
|
|
|
mixin(InitSwitches("", [
|
|
mixin(MakeSwitch([0xC030], "R0W", "toggleSpeaker"))
|
|
]));
|
|
|
|
uint processExtraBuffer(uint elapsed)
|
|
{
|
|
uint newElapsed = elapsed;
|
|
|
|
if (extraIndex != 0)
|
|
{
|
|
for (; extraIndex < extraBuffer.length; ++extraIndex)
|
|
{
|
|
if (newElapsed == 0) break;
|
|
extraBuffer[extraIndex] = sample;
|
|
--newElapsed;
|
|
}
|
|
if (extraIndex == extraBuffer.length)
|
|
{
|
|
extraIndex = 0;
|
|
long sampleMean = 0;
|
|
for (uint i = 0; i < extraBuffer.length; ++i)
|
|
sampleMean += cast(long)extraBuffer[i];
|
|
sampleMean /= cast(long)extraBuffer.length;
|
|
|
|
if (mainIndex < (mainBuffer.length - 1))
|
|
{
|
|
mainBuffer[mainIndex++] =
|
|
(muted ? 0 : cast(short)sampleMean);
|
|
}
|
|
}
|
|
}
|
|
|
|
return newElapsed;
|
|
}
|
|
|
|
void updateExtraBuffer(uint extraTicks)
|
|
{
|
|
if (extraTicks == 0) return;
|
|
|
|
for (extraIndex = 0; extraIndex < extraTicks; ++extraIndex)
|
|
{
|
|
extraBuffer[extraIndex] =
|
|
(muted ? 0 : sample);
|
|
}
|
|
}
|
|
|
|
void update()
|
|
{
|
|
uint elapsedSinceToggle = cycle.val() - lastToggleTick;
|
|
lastToggleTick = cycle.val();
|
|
elapsedSinceToggle = processExtraBuffer(elapsedSinceToggle);
|
|
|
|
uint samples = elapsedSinceToggle / sampleTicks;
|
|
uint extraTicks = elapsedSinceToggle % sampleTicks;
|
|
|
|
// update main buffer
|
|
for (; mainIndex < (mainBuffer.length - 1); ++mainIndex)
|
|
{
|
|
if (samples == 0) break;
|
|
mainBuffer[mainIndex] =
|
|
(muted ? 0 : sample);
|
|
--samples;
|
|
}
|
|
|
|
updateExtraBuffer(extraTicks);
|
|
}
|
|
|
|
void toggleSpeaker()
|
|
{
|
|
toggled = true;
|
|
update();
|
|
sample = ~sample;
|
|
}
|
|
|
|
void clearBuffer()
|
|
{
|
|
mainIndex = 0;
|
|
lastToggleTick = 0;
|
|
toggled = false;
|
|
}
|
|
}
|