mirror of
https://github.com/libretro/hatari.git
synced 2026-11-07 10:36:00 -10:00
Merge pull request #140 from WizzardSK/floppy-led-sound
libretro: drive LEDs and floppy drive sound, from the hatari2014 core
This commit is contained in:
8 files changed
+496
-1
No files matched your search
@@ -1,7 +1,7 @@
|
||||
|
||||
include_directories(. ../.. ../includes ../debug ../falcon libretro-common/include)
|
||||
|
||||
add_library(UiRetro OBJECT audio.c disk_control.c harddisk.c joy_ui.c gui_event.c keymap.c
|
||||
add_library(UiRetro OBJECT audio.c disk_control.c floppy_sound.c harddisk.c joy_ui.c gui_event.c keymap.c
|
||||
main_retro.c microphone.c options.c screen.c statusbar.c timing.c vfs.c)
|
||||
target_include_directories(UiRetro PRIVATE ${LIBRETRO_INCLUDE_DIR})
|
||||
target_compile_definitions(UiRetro PRIVATE LIBRETRO)
|
||||
|
||||
@@ -18,6 +18,7 @@ const char Audio_fileid[] = "Hatari audio.c";
|
||||
#include "dmaSnd.h"
|
||||
#include "crossbar.h"
|
||||
#include "video.h"
|
||||
#include "floppy_sound.h"
|
||||
|
||||
|
||||
bool bSoundWorking = false; /* Is sound OK */
|
||||
@@ -80,12 +81,18 @@ void Audio_Unlock(void)
|
||||
{
|
||||
if (AudioMixBuffer_pos_read + nGeneratedSamples <= AUDIOMIXBUFFER_SIZE)
|
||||
{
|
||||
FloppySound_Mix(&AudioMixBuffer[AudioMixBuffer_pos_read][0],
|
||||
nGeneratedSamples, nAudioFrequency);
|
||||
audio_sample_batch_cb(&AudioMixBuffer[AudioMixBuffer_pos_read][0],
|
||||
nGeneratedSamples);
|
||||
}
|
||||
else
|
||||
{
|
||||
int samples_at_end = AUDIOMIXBUFFER_SIZE - AudioMixBuffer_pos_read;
|
||||
FloppySound_Mix(&AudioMixBuffer[AudioMixBuffer_pos_read][0],
|
||||
samples_at_end, nAudioFrequency);
|
||||
FloppySound_Mix(&AudioMixBuffer[0][0],
|
||||
nGeneratedSamples - samples_at_end, nAudioFrequency);
|
||||
audio_sample_batch_cb(&AudioMixBuffer[AudioMixBuffer_pos_read][0],
|
||||
samples_at_end);
|
||||
audio_sample_batch_cb(&AudioMixBuffer[0][0],
|
||||
|
||||
@@ -0,0 +1,256 @@
|
||||
/*
|
||||
Hatari - floppy_sound.c
|
||||
|
||||
This file is distributed under the GNU General Public License, version 2
|
||||
or at your option any later version. Read the file gpl.txt for details.
|
||||
|
||||
Floppy drive sounds for the libretro core, from the hatari2014 core
|
||||
(libretro/floppy_sound.c there): a click and seek sound when the led of
|
||||
drive A or B comes on, repeated for as long as the floppy controller keeps
|
||||
working on the drive, for both at the same time.
|
||||
|
||||
A sample of one's own can be put in the frontend's system directory as
|
||||
floppy.raw: signed 16-bit little-endian stereo at 44100 Hz, no header
|
||||
(ffmpeg -i click.wav -f s16le -ar 44100 -ac 2 floppy.raw). Without it a
|
||||
synthetic one is used. Both are made to fit the core's audio rate, which
|
||||
can change at run time.
|
||||
*/
|
||||
const char FloppySound_fileid[] = "Hatari floppy_sound.c";
|
||||
|
||||
#include <math.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "main.h"
|
||||
#include "main_retro.h"
|
||||
#include "floppy_sound.h"
|
||||
#include "vfs.h"
|
||||
|
||||
#define RAW_RATE 44100
|
||||
|
||||
static int16_t *raw_pcm; /* floppy.raw as loaded, at RAW_RATE */
|
||||
static int raw_frames;
|
||||
|
||||
static int16_t *sample; /* what is mixed, at sample_rate */
|
||||
static int sample_frames;
|
||||
static int sample_rate;
|
||||
|
||||
static int play_pos[2] = { -1, -1 };
|
||||
static bool enabled = true;
|
||||
static int volume = 192; /* 0-256 */
|
||||
|
||||
|
||||
/**
|
||||
* The built-in sound, ~55 ms: a low mechanical thud, the stepper motor's
|
||||
* buzz, a descending head seek chirp and a short chassis rattle.
|
||||
*/
|
||||
static int16_t *FloppySound_Synthesize(int rate, int *frames)
|
||||
{
|
||||
const float pi = 3.14159265f;
|
||||
int n = rate * 55 / 1000;
|
||||
int16_t *pcm = malloc(n * 2 * sizeof(*pcm));
|
||||
int i;
|
||||
|
||||
if (!pcm)
|
||||
return NULL;
|
||||
|
||||
for (i = 0; i < n; i++)
|
||||
{
|
||||
float t = (float)i / (float)rate;
|
||||
float s = 0.0f;
|
||||
|
||||
/* thud: 120 Hz, decays in ~12 ms */
|
||||
s += sinf(2.0f * pi * 120.0f * t) * expf(-t / 0.012f) * 0.55f;
|
||||
|
||||
/* stepper buzz: ~800 Hz with a wobble, 2 ms onset */
|
||||
{
|
||||
float onset = t > 0.002f ? 1.0f : t / 0.002f;
|
||||
float freq = 800.0f + 60.0f * sinf(2.0f * pi * 180.0f * t);
|
||||
s += sinf(2.0f * pi * freq * t) * onset * expf(-t / 0.008f) * 0.30f;
|
||||
}
|
||||
|
||||
/* head seek chirp: 2400 -> 700 Hz over 25 ms */
|
||||
if (t < 0.025f)
|
||||
{
|
||||
float freq = 2400.0f - 1700.0f * (t / 0.025f);
|
||||
s += sinf(2.0f * pi * freq * t) * expf(-t / 0.018f) * 0.20f;
|
||||
}
|
||||
|
||||
/* rattle: products of unrelated frequencies, 5-17 ms */
|
||||
{
|
||||
float t2 = t - 0.005f;
|
||||
if (t2 > 0.0f && t2 < 0.012f)
|
||||
{
|
||||
float noise = sinf(2.0f * pi * 3700.0f * t2)
|
||||
* sinf(2.0f * pi * 2300.0f * t2)
|
||||
* sinf(2.0f * pi * 970.0f * t2);
|
||||
s += noise * expf(-t2 / 0.005f) * 0.18f;
|
||||
}
|
||||
}
|
||||
|
||||
if (s > 1.0f)
|
||||
s = 1.0f;
|
||||
if (s < -1.0f)
|
||||
s = -1.0f;
|
||||
pcm[i * 2] = pcm[i * 2 + 1] = (int16_t)(s * 28000.0f);
|
||||
}
|
||||
|
||||
*frames = n;
|
||||
return pcm;
|
||||
}
|
||||
|
||||
/**
|
||||
* floppy.raw at another rate, linearly interpolated
|
||||
*/
|
||||
static int16_t *FloppySound_Resample(int rate, int *frames)
|
||||
{
|
||||
int n = (int)((int64_t)raw_frames * rate / RAW_RATE);
|
||||
int16_t *pcm;
|
||||
int i, c;
|
||||
|
||||
if (n <= 0 || !(pcm = malloc(n * 2 * sizeof(*pcm))))
|
||||
return NULL;
|
||||
|
||||
for (i = 0; i < n; i++)
|
||||
{
|
||||
int64_t pos = (int64_t)i * RAW_RATE * 256 / rate;
|
||||
int idx = (int)(pos >> 8), frac = (int)(pos & 255);
|
||||
int next = idx + 1 < raw_frames ? idx + 1 : idx;
|
||||
|
||||
for (c = 0; c < 2; c++)
|
||||
pcm[i * 2 + c] = (int16_t)((raw_pcm[idx * 2 + c] * (256 - frac) +
|
||||
raw_pcm[next * 2 + c] * frac) >> 8);
|
||||
}
|
||||
|
||||
*frames = n;
|
||||
return pcm;
|
||||
}
|
||||
|
||||
static void FloppySound_Prepare(int rate)
|
||||
{
|
||||
free(sample);
|
||||
sample = NULL;
|
||||
sample_frames = 0;
|
||||
sample_rate = rate;
|
||||
|
||||
if (raw_pcm)
|
||||
sample = FloppySound_Resample(rate, &sample_frames);
|
||||
if (!sample)
|
||||
sample = FloppySound_Synthesize(rate, &sample_frames);
|
||||
|
||||
play_pos[0] = play_pos[1] = -1;
|
||||
}
|
||||
|
||||
|
||||
void FloppySound_Init(const char *system_dir)
|
||||
{
|
||||
char path[FILENAME_MAX];
|
||||
VFS_FILE f;
|
||||
int64_t size;
|
||||
|
||||
FloppySound_UnInit();
|
||||
|
||||
if (!system_dir || !system_dir[0])
|
||||
return;
|
||||
|
||||
snprintf(path, sizeof(path), "%s%sfloppy.raw", system_dir, RETRO_PATH_SEPARATOR);
|
||||
f = VFS_fopen(path, "rb");
|
||||
if (!f)
|
||||
return;
|
||||
|
||||
size = VFS_fsize(f);
|
||||
if (size >= 4 && size <= 16 * 1024 * 1024 && (raw_pcm = malloc(size)) != NULL)
|
||||
{
|
||||
if (VFS_fread(raw_pcm, 1, size, f) == (size_t)size)
|
||||
{
|
||||
raw_frames = (int)(size / 4);
|
||||
#if defined(__BYTE_ORDER__) && (__BYTE_ORDER__ == __ORDER_BIG_ENDIAN__)
|
||||
{
|
||||
int i;
|
||||
for (i = 0; i < raw_frames * 2; i++)
|
||||
{
|
||||
uint16_t v = (uint16_t)raw_pcm[i];
|
||||
raw_pcm[i] = (int16_t)((v >> 8) | (v << 8));
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
else
|
||||
{
|
||||
free(raw_pcm);
|
||||
raw_pcm = NULL;
|
||||
}
|
||||
}
|
||||
VFS_fclose(f);
|
||||
}
|
||||
|
||||
void FloppySound_UnInit(void)
|
||||
{
|
||||
free(raw_pcm);
|
||||
raw_pcm = NULL;
|
||||
raw_frames = 0;
|
||||
free(sample);
|
||||
sample = NULL;
|
||||
sample_frames = 0;
|
||||
sample_rate = 0;
|
||||
play_pos[0] = play_pos[1] = -1;
|
||||
}
|
||||
|
||||
void FloppySound_SetEnabled(bool on)
|
||||
{
|
||||
enabled = on;
|
||||
if (!on)
|
||||
play_pos[0] = play_pos[1] = -1;
|
||||
}
|
||||
|
||||
void FloppySound_SetVolume(int percent)
|
||||
{
|
||||
volume = percent * 256 / 100;
|
||||
}
|
||||
|
||||
void FloppySound_Trigger(int drive)
|
||||
{
|
||||
if (enabled && (drive == 0 || drive == 1))
|
||||
play_pos[drive] = 0;
|
||||
}
|
||||
|
||||
bool FloppySound_Playing(int drive)
|
||||
{
|
||||
return (drive == 0 || drive == 1) && play_pos[drive] >= 0;
|
||||
}
|
||||
|
||||
void FloppySound_Mix(int16_t *buf, int frames, int rate)
|
||||
{
|
||||
int d, i;
|
||||
|
||||
if (!enabled || rate <= 0 || (play_pos[0] < 0 && play_pos[1] < 0))
|
||||
return;
|
||||
|
||||
if (rate != sample_rate)
|
||||
{
|
||||
int pos[2] = { play_pos[0], play_pos[1] };
|
||||
FloppySound_Prepare(rate);
|
||||
play_pos[0] = pos[0] >= 0 ? 0 : -1;
|
||||
play_pos[1] = pos[1] >= 0 ? 0 : -1;
|
||||
}
|
||||
if (!sample)
|
||||
return;
|
||||
|
||||
for (d = 0; d < 2; d++)
|
||||
{
|
||||
if (play_pos[d] < 0)
|
||||
continue;
|
||||
|
||||
for (i = 0; i < frames && play_pos[d] < sample_frames; i++, play_pos[d]++)
|
||||
{
|
||||
int l = buf[i * 2] + ((sample[play_pos[d] * 2] * volume) >> 8);
|
||||
int r = buf[i * 2 + 1] + ((sample[play_pos[d] * 2 + 1] * volume) >> 8);
|
||||
buf[i * 2] = l > 32767 ? 32767 : l < -32768 ? -32768 : l;
|
||||
buf[i * 2 + 1] = r > 32767 ? 32767 : r < -32768 ? -32768 : r;
|
||||
}
|
||||
|
||||
if (play_pos[d] >= sample_frames)
|
||||
play_pos[d] = -1;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
/*
|
||||
Hatari - floppy_sound.h
|
||||
|
||||
This file is distributed under the GNU General Public License, version 2
|
||||
or at your option any later version. Read the file gpl.txt for details.
|
||||
*/
|
||||
|
||||
#ifndef HATARI_RETRO_FLOPPY_SOUND_H
|
||||
#define HATARI_RETRO_FLOPPY_SOUND_H
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
|
||||
/* Load floppy.raw from the system directory, if there is one */
|
||||
void FloppySound_Init(const char *system_dir);
|
||||
void FloppySound_UnInit(void);
|
||||
|
||||
void FloppySound_SetEnabled(bool enabled);
|
||||
void FloppySound_SetVolume(int percent);
|
||||
|
||||
/* Start the drive sound for drive 0 (A) or 1 (B) */
|
||||
void FloppySound_Trigger(int drive);
|
||||
|
||||
/* Whether the sound for drive 0 (A) or 1 (B) is still playing */
|
||||
bool FloppySound_Playing(int drive);
|
||||
|
||||
/* Mix the playing drive sounds into 'frames' stereo frames at 'rate' Hz */
|
||||
void FloppySound_Mix(int16_t *buf, int frames, int rate);
|
||||
|
||||
#endif /* ifndef HATARI_RETRO_FLOPPY_SOUND_H */
|
||||
@@ -13,6 +13,7 @@
|
||||
#include "disk_control.h"
|
||||
#include "file.h"
|
||||
#include "floppy.h"
|
||||
#include "floppy_sound.h"
|
||||
#include "harddisk.h"
|
||||
#include "memorySnapShot.h"
|
||||
#include "m68000.h"
|
||||
@@ -20,6 +21,7 @@
|
||||
#include "reset.h"
|
||||
#include "screen.h"
|
||||
#include "sound.h"
|
||||
#include "statusbar.h"
|
||||
#include "tos.h"
|
||||
#include "vdi.h"
|
||||
#include "version.h"
|
||||
@@ -179,6 +181,7 @@ RETRO_API void retro_init(void)
|
||||
if (environment_cb(RETRO_ENVIRONMENT_GET_SYSTEM_DIRECTORY, &system_dir) && system_dir)
|
||||
{
|
||||
retro_system_directory = system_dir;
|
||||
FloppySound_Init(system_dir);
|
||||
|
||||
snprintf(tos_path, sizeof(tos_path), "%s%s%s",
|
||||
system_dir, RETRO_PATH_SEPARATOR, "tos.img");
|
||||
@@ -210,6 +213,7 @@ RETRO_API void retro_deinit(void)
|
||||
{
|
||||
scratch_path[0] = '\0';
|
||||
Main_UnInit();
|
||||
FloppySound_UnInit();
|
||||
}
|
||||
|
||||
RETRO_API void retro_get_system_info(struct retro_system_info *info)
|
||||
@@ -247,6 +251,34 @@ RETRO_API void retro_reset(void)
|
||||
Reset_Warm();
|
||||
}
|
||||
|
||||
/**
|
||||
* The frame with the drive leds drawn over it, in a
|
||||
* copy: the emulator's own buffer is not drawn anew every frame where the
|
||||
* picture stays the same.
|
||||
*/
|
||||
static uint32_t *Core_DrawOverlays(uint32_t *pixels, int width, int height, int pitch)
|
||||
{
|
||||
static uint32_t *overlay;
|
||||
static size_t overlay_size;
|
||||
size_t size = (size_t)pitch * height;
|
||||
|
||||
if (!pixels || !Statusbar_LedsVisible())
|
||||
return pixels;
|
||||
|
||||
if (size > overlay_size)
|
||||
{
|
||||
uint32_t *bigger = realloc(overlay, size);
|
||||
if (!bigger)
|
||||
return pixels;
|
||||
overlay = bigger;
|
||||
overlay_size = size;
|
||||
}
|
||||
memcpy(overlay, pixels, size);
|
||||
|
||||
Statusbar_DrawLeds(overlay, width, height, pitch);
|
||||
return overlay;
|
||||
}
|
||||
|
||||
RETRO_API void retro_run(void)
|
||||
{
|
||||
bool options_updated = false;
|
||||
@@ -282,7 +314,9 @@ RETRO_API void retro_run(void)
|
||||
}
|
||||
|
||||
Screen_GetDimension(&pixels, &width, &height, &pitch);
|
||||
pixels = Core_DrawOverlays(pixels, width, height, pitch);
|
||||
video_refresh_cb(pixels, width, height, pitch);
|
||||
Statusbar_FrameDone();
|
||||
}
|
||||
|
||||
RETRO_API void retro_set_controller_port_device(unsigned port, unsigned device)
|
||||
|
||||
@@ -21,3 +21,9 @@ extern retro_video_refresh_t video_refresh_cb;
|
||||
extern retro_input_state_t input_state_cb;
|
||||
extern void Core_RefreshRateChanged(void);
|
||||
extern void Retro_Log(int nType, const char *msg);
|
||||
|
||||
/* statusbar.c: the drive leds, drawn over the frame */
|
||||
void Statusbar_ShowLeds(bool show);
|
||||
bool Statusbar_LedsVisible(void);
|
||||
void Statusbar_DrawLeds(uint32_t *pixels, int width, int height, int pitch);
|
||||
void Statusbar_FrameDone(void);
|
||||
@@ -9,6 +9,7 @@
|
||||
|
||||
#include "configuration.h"
|
||||
#include "fdc.h"
|
||||
#include "floppy_sound.h"
|
||||
#include "main_retro.h"
|
||||
#include "options.h"
|
||||
#include "reset.h"
|
||||
@@ -350,6 +351,50 @@ static struct retro_core_option_v2_definition option_defs_us[] = {
|
||||
},
|
||||
"off"
|
||||
},
|
||||
{
|
||||
"hatari_drive_leds",
|
||||
"Drive LEDs",
|
||||
"Drive LEDs",
|
||||
"Show drive activity in the top right corner of the screen: an amber LED per floppy drive, as on an STFM, and a green one for the hard disk.",
|
||||
NULL,
|
||||
"floppy",
|
||||
{
|
||||
{ "enabled", NULL },
|
||||
{ "disabled", NULL },
|
||||
{ NULL, NULL },
|
||||
},
|
||||
"enabled"
|
||||
},
|
||||
{
|
||||
"hatari_floppy_sound",
|
||||
"Floppy Drive Sound",
|
||||
"Floppy Drive Sound",
|
||||
"Play a mechanical floppy drive sound when a drive is accessed. For a sound of your own, put floppy.raw (signed 16-bit stereo at 44100 Hz, no header) in the frontend's system directory.",
|
||||
NULL,
|
||||
"floppy",
|
||||
{
|
||||
{ "enabled", NULL },
|
||||
{ "disabled", NULL },
|
||||
{ NULL, NULL },
|
||||
},
|
||||
"enabled"
|
||||
},
|
||||
{
|
||||
"hatari_floppy_sound_volume",
|
||||
"Floppy Drive Sound Volume",
|
||||
"Floppy Drive Sound Volume",
|
||||
"Volume of the floppy drive sound.",
|
||||
NULL,
|
||||
"floppy",
|
||||
{
|
||||
{ "25", "25%" },
|
||||
{ "50", "50%" },
|
||||
{ "75", "75%" },
|
||||
{ "100", "100%" },
|
||||
{ NULL, NULL },
|
||||
},
|
||||
"75"
|
||||
},
|
||||
{
|
||||
"hatari_drive_a_enable",
|
||||
"Drive A Enabled",
|
||||
@@ -817,6 +862,10 @@ void Core_ApplyRuntimeOptions(void)
|
||||
FDC_Drive_Set_Enable(1, ConfigureParams.DiskImage.EnableDriveB);
|
||||
FDC_Drive_Set_NumberOfHeads(0, ConfigureParams.DiskImage.DriveA_NumberOfHeads);
|
||||
FDC_Drive_Set_NumberOfHeads(1, ConfigureParams.DiskImage.DriveB_NumberOfHeads);
|
||||
|
||||
Statusbar_ShowLeds(Core_VarBool("hatari_drive_leds", true));
|
||||
FloppySound_SetEnabled(Core_VarBool("hatari_floppy_sound", true));
|
||||
FloppySound_SetVolume(Core_VarInt("hatari_floppy_sound_volume", 75));
|
||||
|
||||
/* --- Atari Screen --- */
|
||||
str = Core_VarStr("hatari_monitor_type", "rgb");
|
||||
|
||||
@@ -5,6 +5,11 @@
|
||||
or at your option any later version. Read the file gpl.txt for details.
|
||||
|
||||
Code to draw statusbar area, floppy leds etc.
|
||||
|
||||
The libretro core has no statusbar area: the drive LEDs are drawn over the
|
||||
top right corner of the frame instead, a small amber bar per floppy drive
|
||||
like the one on an STFM, and a green one for the hard disk (from the
|
||||
hatari2014 core). A floppy LED going on also starts the drive sound.
|
||||
*/
|
||||
const char Statusbar_fileid[] = "Hatari statusbar.c";
|
||||
|
||||
@@ -23,8 +28,17 @@ const char Statusbar_fileid[] = "Hatari statusbar.c";
|
||||
#include "blitter.h"
|
||||
#include "str.h"
|
||||
#include "lilo.h"
|
||||
#include "floppy_sound.h"
|
||||
#include "main_retro.h"
|
||||
|
||||
|
||||
#define HD_LED_FRAMES 10 /* frames the HD led stays on */
|
||||
|
||||
static bool leds_shown = true;
|
||||
static drive_led_t floppy_led[2];
|
||||
static bool floppy_busy[2]; /* the controller has worked on the drive this frame */
|
||||
static int hd_led_frames;
|
||||
|
||||
/**
|
||||
* Return statusbar height for given width and height
|
||||
*/
|
||||
@@ -59,6 +73,8 @@ int Statusbar_GetHeight(void)
|
||||
*/
|
||||
void Statusbar_EnableHDLed(drive_led_t state)
|
||||
{
|
||||
if (state != LED_STATE_OFF)
|
||||
hd_led_frames = HD_LED_FRAMES;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -68,8 +84,105 @@ void Statusbar_EnableHDLed(drive_led_t state)
|
||||
void Statusbar_SetFloppyLed(drive_index_t drive, drive_led_t state)
|
||||
{
|
||||
assert(drive == DRIVE_LED_A || drive == DRIVE_LED_B);
|
||||
|
||||
if (state == LED_STATE_ON_BUSY)
|
||||
floppy_busy[drive] = true;
|
||||
floppy_led[drive] = state;
|
||||
}
|
||||
|
||||
/**
|
||||
* Show or hide the drive leds drawn over the frame
|
||||
*/
|
||||
void Statusbar_ShowLeds(bool show)
|
||||
{
|
||||
leds_shown = show;
|
||||
}
|
||||
|
||||
/**
|
||||
* Whether any drive led is to be drawn over this frame
|
||||
*/
|
||||
bool Statusbar_LedsVisible(void)
|
||||
{
|
||||
return leds_shown && (floppy_led[0] != LED_STATE_OFF ||
|
||||
floppy_led[1] != LED_STATE_OFF || hd_led_frames > 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Once per retro_run: what times the HD led out, and what starts the floppy
|
||||
* sound. Drive leds are looked at once a frame, as the hatari2014 core did:
|
||||
* the sound starts when a led has come on since the last frame, and plays
|
||||
* again each time it has finished for as long as the controller has worked
|
||||
* on the drive during the frame - so a load sounds for as long as it lasts,
|
||||
* and the sample is never cut off to start it over. TOS selecting drive A
|
||||
* and B in turn every eight VBLs to check for a disk change is over within
|
||||
* the frame and carries out no command, so it is not heard.
|
||||
*/
|
||||
void Statusbar_FrameDone(void)
|
||||
{
|
||||
static bool was_on[2];
|
||||
int d;
|
||||
|
||||
for (d = 0; d < 2; d++)
|
||||
{
|
||||
bool on = floppy_led[d] != LED_STATE_OFF;
|
||||
bool busy = floppy_busy[d] || floppy_led[d] == LED_STATE_ON_BUSY;
|
||||
if ((on && !was_on[d]) || (busy && !FloppySound_Playing(d)))
|
||||
FloppySound_Trigger(d);
|
||||
was_on[d] = on;
|
||||
floppy_busy[d] = false;
|
||||
}
|
||||
|
||||
if (hd_led_frames > 0)
|
||||
hd_led_frames--;
|
||||
}
|
||||
|
||||
/**
|
||||
* Draw the drive leds into a copy of the frame about to be handed to the
|
||||
* frontend
|
||||
*/
|
||||
void Statusbar_DrawLeds(uint32_t *pixels, int width, int height, int pitch)
|
||||
{
|
||||
static const uint32_t floppy_color = 0xF8D800; /* STFM amber */
|
||||
static const uint32_t hd_color = 0x30E030;
|
||||
bool on[3];
|
||||
int led_w, led_h, gap, right, top, i, x, y;
|
||||
int stride = pitch / 4;
|
||||
|
||||
if (!Statusbar_LedsVisible() || !pixels)
|
||||
return;
|
||||
|
||||
on[0] = floppy_led[0] != LED_STATE_OFF;
|
||||
on[1] = floppy_led[1] != LED_STATE_OFF;
|
||||
on[2] = hd_led_frames > 0;
|
||||
|
||||
/* The hatari2014 core's 13x5 bar in a 384 pixel wide frame, scaled */
|
||||
led_w = width * 13 / 384;
|
||||
led_h = height * 5 / 276;
|
||||
if (led_w < 7)
|
||||
led_w = 7;
|
||||
if (led_w > 64)
|
||||
led_w = 64;
|
||||
if (led_h < 3)
|
||||
led_h = 3;
|
||||
if (led_h > 16)
|
||||
led_h = 16;
|
||||
gap = led_w / 2;
|
||||
right = width - led_w / 2;
|
||||
top = led_h;
|
||||
if (right - 3 * led_w - 2 * gap < 0 || top + led_h > height)
|
||||
return;
|
||||
|
||||
/* A rightmost, then B, then the hard disk */
|
||||
for (i = 0; i < 3; i++)
|
||||
{
|
||||
int left = right - (i + 1) * led_w - i * gap;
|
||||
if (!on[i])
|
||||
continue;
|
||||
for (y = top; y < top + led_h; y++)
|
||||
for (x = left; x < left + led_w; x++)
|
||||
pixels[y * stride + x] = i < 2 ? floppy_color : hd_color;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Set TOS etc information and initial help message
|
||||
|
||||
Reference in new issue
Block a user