Merge remote-tracking branch '86box/v0.5_fdd_audio_multitrack_seek_sound_effects'

This commit is contained in:
Toni Riikonen
2025-09-08 21:00:52 +03:00
26 changed files with 904 additions and 115 deletions

BIN
86box/86Box.exe Normal file

Binary file not shown.

0
src/.vs/CMake Overview Normal file
View File

View File

@@ -0,0 +1,3 @@
{
"CurrentProjectSetting": "x64-Debug"
}

View File

@@ -0,0 +1,12 @@
{
"OutputFoldersPerTargetSystem": {
"Local Machine": [
"out\\build\\x64-Debug",
"out\\install\\x64-Debug"
]
},
"ExpandedNodes": [
""
],
"PreviewInSolutionExplorer": false
}

BIN
src/.vs/slnx.sqlite Normal file

Binary file not shown.

BIN
src/.vs/src/v17/.wsuo Normal file

Binary file not shown.

Binary file not shown.

View File

@@ -0,0 +1,61 @@
{
"Version": 1,
"WorkspaceRootPath": "D:\\msys64\\home\\dompp\\86Box\\src\\",
"Documents": [
{
"AbsoluteMoniker": "D:0:0:{A2FE74E1-B743-11D0-AE1A-00A0C90FFFC3}|\u003CMiscFiles\u003E|D:\\msys64\\home\\dompp\\86Box\\src\\CMakeSettings.json||{10608CD5-279C-4A28-BD5F-BA2CFCE06219}",
"RelativeMoniker": "D:0:0:{A2FE74E1-B743-11D0-AE1A-00A0C90FFFC3}|\u003CMiscFiles\u003E|solutionrelative:CMakeSettings.json||{10608CD5-279C-4A28-BD5F-BA2CFCE06219}"
},
{
"AbsoluteMoniker": "D:0:0:{A2FE74E1-B743-11D0-AE1A-00A0C90FFFC3}|\u003CMiscFiles\u003E|CMake Overview Pages||{B1CAA5B0-FEB1-4350-8AB9-F895876842F2}"
}
],
"DocumentGroupContainers": [
{
"Orientation": 0,
"VerticalTabListWidth": 256,
"DocumentGroups": [
{
"DockedWidth": 200,
"SelectedChildIndex": 3,
"Children": [
{
"$type": "Bookmark",
"Name": "ST:0:0:{65ddf8c3-8f89-4077-a6c6-dbb8853aab13}"
},
{
"$type": "Bookmark",
"Name": "ST:11:0:{2456bd12-ecf7-4988-a4a6-67d49173f565}"
},
{
"$type": "Bookmark",
"Name": "ST:12:0:{2456bd12-ecf7-4988-a4a6-67d49173f565}"
},
{
"$type": "Document",
"DocumentIndex": 0,
"Title": "CMakeSettings.json",
"DocumentMoniker": "D:\\msys64\\home\\dompp\\86Box\\src\\CMakeSettings.json",
"RelativeDocumentMoniker": "CMakeSettings.json",
"ToolTip": "D:\\msys64\\home\\dompp\\86Box\\src\\CMakeSettings.json",
"RelativeToolTip": "CMakeSettings.json",
"Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.001642|",
"WhenOpened": "2025-08-30T19:09:23.796Z",
"EditorCaption": ""
},
{
"$type": "Document",
"DocumentIndex": 1,
"Title": "CMake Overview Pages",
"DocumentMoniker": "CMake Overview Pages",
"ToolTip": "CMake Overview Pages",
"Icon": "ae27a6b0-e345-4288-96df-5eaf394ee369.001001|",
"WhenOpened": "2025-08-30T19:09:12.336Z",
"EditorCaption": ""
}
]
}
]
}
]
}

Binary file not shown.

15
src/CMakeSettings.json Normal file
View File

@@ -0,0 +1,15 @@
{
"configurations": [
{
"name": "x64-Debug",
"generator": "Ninja",
"configurationType": "Debug",
"inheritEnvironments": [ "msvc_x64_x64" ],
"buildRoot": "${projectDir}\\out\\build\\${name}",
"installRoot": "${projectDir}\\out\\install\\${name}",
"cmakeCommandArgs": "",
"buildCommandArgs": "",
"ctestCommandArgs": ""
}
]
}

View File

@@ -10,9 +10,12 @@
#
# Authors: David Hrdlička, <hrdlickadavid@outlook.com>
# Jasmine Iwanek, <jriwanek@gmail.com>
# Toni Riikonen, <riikonen.toni@gmail.com>
#
# Copyright 2020-2021 David Hrdlička.
# Copyright 2024 Jasmine Iwanek.
# Copyright 2025 Toni Riikonen.
# All rights reserved.
#
add_library(fdd OBJECT
@@ -31,6 +34,7 @@ add_library(fdd OBJECT
fdd_pcjs.c
fdd_mfm.c
fdd_td0.c
fdd_audio.c
)
add_subdirectory(lzw)

View File

@@ -23,6 +23,8 @@
#include <stdio.h>
#include <string.h>
#include <wchar.h>
#include <stdlib.h>
#define HAVE_STDARG_H
#include <86box/86box.h>
#include <86box/timer.h>
@@ -39,6 +41,7 @@
#include <86box/fdd_mfm.h>
#include <86box/fdd_td0.h>
#include <86box/fdc.h>
#include <86box/fdd_audio.h>
/* Flags:
Bit 0: 300 rpm supported;
@@ -88,7 +91,7 @@ int writeprot[FDD_NUM];
int fwriteprot[FDD_NUM];
int fdd_changed[FDD_NUM];
int ui_writeprot[FDD_NUM] = { 0, 0, 0, 0 };
int drive_empty[FDD_NUM] = { 1, 1, 1, 1 };
int drive_empty[FDD_NUM] = { 1, 1, 1, 1 };
DRIVE drives[FDD_NUM];
@@ -101,43 +104,43 @@ d86f_handler_t d86f_handler[FDD_NUM];
static const struct
{
const char *ext;
void (*load)(int drive, char *fn);
void (*close)(int drive);
int size;
void (*load)(int drive, char *fn);
void (*close)(int drive);
int size;
} loaders[] = {
{ "001", img_load, img_close, -1},
{ "002", img_load, img_close, -1},
{ "003", img_load, img_close, -1},
{ "004", img_load, img_close, -1},
{ "005", img_load, img_close, -1},
{ "006", img_load, img_close, -1},
{ "007", img_load, img_close, -1},
{ "008", img_load, img_close, -1},
{ "009", img_load, img_close, -1},
{ "010", img_load, img_close, -1},
{ "12", img_load, img_close, -1},
{ "144", img_load, img_close, -1},
{ "360", img_load, img_close, -1},
{ "720", img_load, img_close, -1},
{ "86F", d86f_load, d86f_close, -1},
{ "BIN", img_load, img_close, -1},
{ "CQ", img_load, img_close, -1},
{ "CQM", img_load, img_close, -1},
{ "DDI", img_load, img_close, -1},
{ "DSK", img_load, img_close, -1},
{ "FDI", fdi_load, fdi_close, -1},
{ "FDF", img_load, img_close, -1},
{ "FLP", img_load, img_close, -1},
{ "HDM", img_load, img_close, -1},
{ "IMA", img_load, img_close, -1},
{ "IMD", imd_load, imd_close, -1},
{ "IMG", img_load, img_close, -1},
{ "JSON", pcjs_load, pcjs_close, -1},
{ "MFM", mfm_load, mfm_close, -1},
{ "TD0", td0_load, td0_close, -1},
{ "VFD", img_load, img_close, -1},
{ "XDF", img_load, img_close, -1},
{ 0, 0, 0, 0 }
{ "001", img_load, img_close, -1 },
{ "002", img_load, img_close, -1 },
{ "003", img_load, img_close, -1 },
{ "004", img_load, img_close, -1 },
{ "005", img_load, img_close, -1 },
{ "006", img_load, img_close, -1 },
{ "007", img_load, img_close, -1 },
{ "008", img_load, img_close, -1 },
{ "009", img_load, img_close, -1 },
{ "010", img_load, img_close, -1 },
{ "12", img_load, img_close, -1 },
{ "144", img_load, img_close, -1 },
{ "360", img_load, img_close, -1 },
{ "720", img_load, img_close, -1 },
{ "86F", d86f_load, d86f_close, -1 },
{ "BIN", img_load, img_close, -1 },
{ "CQ", img_load, img_close, -1 },
{ "CQM", img_load, img_close, -1 },
{ "DDI", img_load, img_close, -1 },
{ "DSK", img_load, img_close, -1 },
{ "FDI", fdi_load, fdi_close, -1 },
{ "FDF", img_load, img_close, -1 },
{ "FLP", img_load, img_close, -1 },
{ "HDM", img_load, img_close, -1 },
{ "IMA", img_load, img_close, -1 },
{ "IMD", imd_load, imd_close, -1 },
{ "IMG", img_load, img_close, -1 },
{ "JSON", pcjs_load, pcjs_close, -1 },
{ "MFM", mfm_load, mfm_close, -1 },
{ "TD0", td0_load, td0_close, -1 },
{ "VFD", img_load, img_close, -1 },
{ "XDF", img_load, img_close, -1 },
{ 0, 0, 0, 0 }
};
static const struct {
@@ -147,35 +150,35 @@ static const struct {
const char *internal_name;
} drive_types[] = {
/* None */
{ 0, 0, "None", "none" },
{ 0, 0, "None", "none" },
/* 5.25" 1DD */
{ 43, FLAG_RPM_300 | FLAG_525 | FLAG_HOLE0, "5.25\" 180k", "525_1dd" },
{ 43, FLAG_RPM_300 | FLAG_525 | FLAG_HOLE0, "5.25\" 180k", "525_1dd" },
/* 5.25" DD */
{ 43, FLAG_RPM_300 | FLAG_525 | FLAG_DS | FLAG_HOLE0, "5.25\" 360k", "525_2dd" },
{ 43, FLAG_RPM_300 | FLAG_525 | FLAG_DS | FLAG_HOLE0, "5.25\" 360k", "525_2dd" },
/* 5.25" QD */
{ 86, FLAG_RPM_300 | FLAG_525 | FLAG_DS | FLAG_HOLE0 | FLAG_DOUBLE_STEP, "5.25\" 720k", "525_2qd" },
{ 86, FLAG_RPM_300 | FLAG_525 | FLAG_DS | FLAG_HOLE0 | FLAG_DOUBLE_STEP, "5.25\" 720k", "525_2qd" },
/* 5.25" HD */
{ 86, FLAG_RPM_360 | FLAG_525 | FLAG_DS | FLAG_HOLE0 | FLAG_HOLE1 | FLAG_DOUBLE_STEP | FLAG_PS2, "5.25\" 1.2M", "525_2hd" },
{ 86, FLAG_RPM_360 | FLAG_525 | FLAG_DS | FLAG_HOLE0 | FLAG_HOLE1 | FLAG_DOUBLE_STEP | FLAG_PS2, "5.25\" 1.2M", "525_2hd" },
/* 5.25" HD Dual RPM */
{ 86, FLAG_RPM_300 | FLAG_RPM_360 | FLAG_525 | FLAG_DS | FLAG_HOLE0 | FLAG_HOLE1 | FLAG_DOUBLE_STEP, "5.25\" 1.2M 300/360 RPM", "525_2hd_dualrpm" },
{ 86, FLAG_RPM_300 | FLAG_RPM_360 | FLAG_525 | FLAG_DS | FLAG_HOLE0 | FLAG_HOLE1 | FLAG_DOUBLE_STEP, "5.25\" 1.2M 300/360 RPM", "525_2hd_dualrpm" },
/* 3.5" 1DD */
{ 86, FLAG_RPM_300 | FLAG_HOLE0 | FLAG_DOUBLE_STEP, "3.5\" 360k", "35_1dd" },
{ 86, FLAG_RPM_300 | FLAG_HOLE0 | FLAG_DOUBLE_STEP, "3.5\" 360k", "35_1dd" },
/* 3.5" DD, Equivalent to TEAC FD-235F */
{ 86, FLAG_RPM_300 | FLAG_DS | FLAG_HOLE0 | FLAG_DOUBLE_STEP, "3.5\" 720k", "35_2dd" },
{ 86, FLAG_RPM_300 | FLAG_DS | FLAG_HOLE0 | FLAG_DOUBLE_STEP, "3.5\" 720k", "35_2dd" },
/* 3.5" HD, Equivalent to TEAC FD-235HF */
{ 86, FLAG_RPM_300 | FLAG_DS | FLAG_HOLE0 | FLAG_HOLE1 | FLAG_DOUBLE_STEP | FLAG_PS2, "3.5\" 1.44M", "35_2hd" },
{ 86, FLAG_RPM_300 | FLAG_DS | FLAG_HOLE0 | FLAG_HOLE1 | FLAG_DOUBLE_STEP | FLAG_PS2, "3.5\" 1.44M", "35_2hd" },
/* TODO: 3.5" DD, Equivalent to TEAC FD-235GF */
// { 86, FLAG_RPM_300 | FLAG_RPM_360 | FLAG_DS | FLAG_HOLE0 | FLAG_HOLE1 | FLAG_DOUBLE_STEP, "3.5\" 1.25M", "35_2hd_2mode" },
// { 86, FLAG_RPM_300 | FLAG_RPM_360 | FLAG_DS | FLAG_HOLE0 | FLAG_HOLE1 | FLAG_DOUBLE_STEP, "3.5\" 1.25M", "35_2hd_2mode" },
/* 3.5" HD PC-98 */
{ 86, FLAG_RPM_300 | FLAG_RPM_360 | FLAG_DS | FLAG_HOLE0 | FLAG_HOLE1 | FLAG_DOUBLE_STEP | FLAG_INVERT_DENSEL, "3.5\" 1.25M PC-98", "35_2hd_nec" },
{ 86, FLAG_RPM_300 | FLAG_RPM_360 | FLAG_DS | FLAG_HOLE0 | FLAG_HOLE1 | FLAG_DOUBLE_STEP | FLAG_INVERT_DENSEL, "3.5\" 1.25M PC-98", "35_2hd_nec" },
/* 3.5" HD 3-Mode, Equivalent to TEAC FD-235HG */
{ 86, FLAG_RPM_300 | FLAG_RPM_360 | FLAG_DS | FLAG_HOLE0 | FLAG_HOLE1 | FLAG_DOUBLE_STEP, "3.5\" 1.44M 300/360 RPM", "35_2hd_3mode" },
{ 86, FLAG_RPM_300 | FLAG_RPM_360 | FLAG_DS | FLAG_HOLE0 | FLAG_HOLE1 | FLAG_DOUBLE_STEP, "3.5\" 1.44M 300/360 RPM", "35_2hd_3mode" },
/* 3.5" ED, Equivalent to TEAC FD-235J */
{ 86, FLAG_RPM_300 | FLAG_DS | FLAG_HOLE0 | FLAG_HOLE1 | FLAG_HOLE2 | FLAG_DOUBLE_STEP, "3.5\" 2.88M", "35_2ed" },
{ 86, FLAG_RPM_300 | FLAG_DS | FLAG_HOLE0 | FLAG_HOLE1 | FLAG_HOLE2 | FLAG_DOUBLE_STEP, "3.5\" 2.88M", "35_2ed" },
/* 3.5" ED Dual RPM, Equivalent to TEAC FD-335J */
{ 86, FLAG_RPM_300 | FLAG_RPM_360 | FLAG_DS | FLAG_HOLE0 | FLAG_HOLE1 | FLAG_HOLE2 | FLAG_DOUBLE_STEP, "3.5\" 2.88M 300/360 RPM", "35_2ed_dualrpm" },
{ 86, FLAG_RPM_300 | FLAG_RPM_360 | FLAG_DS | FLAG_HOLE0 | FLAG_HOLE1 | FLAG_HOLE2 | FLAG_DOUBLE_STEP, "3.5\" 2.88M 300/360 RPM", "35_2ed_dualrpm" },
/* End of list */
{ -1, -1, "", "" }
{ -1, -1, "", "" }
};
#ifdef ENABLE_FDD_LOG
@@ -211,7 +214,7 @@ fdd_get_internal_name(int type)
int
fdd_get_from_internal_name(char *s)
{
int c = 0;
int c = 0;
while (strlen(drive_types[c].internal_name)) {
if (!strcmp((char *) drive_types[c].internal_name, s))
@@ -250,6 +253,8 @@ fdd_seek(int drive, int track_diff)
if (!track_diff)
return;
int old_track = fdd[drive].track;
fdd[drive].track += track_diff;
if (fdd[drive].track < 0)
@@ -260,6 +265,16 @@ fdd_seek(int drive, int track_diff)
fdd_changed[drive] = 0;
/* Trigger appropriate audio for track movements */
int actual_track_diff = abs(old_track - fdd[drive].track);
if (actual_track_diff == 1) {
/* Single track movement */
fdd_audio_play_single_track_step(drive, old_track, fdd[drive].track);
} else if (actual_track_diff > 1) {
/* Multi-track seek */
fdd_audio_play_multi_track_seek(drive, old_track, fdd[drive].track);
}
fdd_do_seek(drive, fdd[drive].track);
}
@@ -461,12 +476,10 @@ fdd_load(int drive, char *fn)
FILE *fp;
int offs = 0;
fdd_log("FDD: loading drive %d with '%s'\n", drive, fn);
if (!fn)
return;
if (strstr(fn, "wp://") == fn) {
offs = 5;
offs = 5;
ui_writeprot[drive] = 1;
}
fn += offs;
@@ -495,7 +508,6 @@ fdd_load(int drive, char *fn)
c++;
}
}
fdd_log("FDD: could not load '%s' %s\n", fn, p);
drive_empty[drive] = 1;
fdd_set_head(drive, 0);
memset(floppyfns[drive], 0, sizeof(floppyfns[drive]));
@@ -505,8 +517,6 @@ fdd_load(int drive, char *fn)
void
fdd_close(int drive)
{
fdd_log("FDD: closing drive %d\n", drive);
d86f_stop(drive); /* Call this first of all to make sure the 86F poll is back to idle state. */
if (loaders[driveloaders[drive]].close)
loaders[driveloaders[drive]].close(drive);
@@ -548,11 +558,13 @@ fdd_byteperiod(int drive)
void
fdd_set_motor_enable(int drive, int motor_enable)
{
/* I think here is where spin-up and spin-down should be implemented. */
if (motor_enable && !motoron[drive])
fdd_audio_set_motor_enable(drive, motor_enable);
if (motor_enable && !motoron[drive]) {
timer_set_delay_u64(&fdd_poll_time[drive], fdd_byteperiod(drive));
else if (!motor_enable)
} else if (!motor_enable && motoron[drive]) {
timer_disable(&fdd_poll_time[drive]);
}
motoron[drive] = motor_enable;
}
@@ -690,10 +702,12 @@ fdd_init(void)
for (i = 0; i < FDD_NUM; i++) {
fdd_load(i, floppyfns[i]);
}
fdd_audio_init();
}
void
fdd_do_writeback(int drive)
{
d86f_handler[drive].writeback(drive);
}
}

492
src/floppy/fdd_audio.c Normal file
View File

@@ -0,0 +1,492 @@
/*
* 86Box A hypervisor and IBM PC system emulator that specializes in
* running old operating systems and software designed for IBM
* PC systems and compatibles from 1981 through fairly recent
* system designs based on the PCI bus.
*
* This file is part of the 86Box distribution.
*
* Implementation of the floppy drive audio emulation.
*
* Authors: Toni Riikonen, <riikonen.toni@gmail.com>
*
* Copyright 2025 Toni Riikonen.
*/
#include <stdarg.h>
#include <stdint.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#define HAVE_STDARG_H
#include <86box/86box.h>
#include <86box/timer.h>
#include <86box/fdd.h>
#include <86box/fdd_audio.h>
#include <86box/sound.h>
// TODO:
// OK 1. Implement spindle motor spin-up and spin-down
// OK 2. Move audio emulation to separate code file
// OK 3. Implement sound support for all drives (not only for drive 0)
// OK 4. Single sector read/write sound emulation
// OK 5. Multi-track seek sound emulation
// 6. Limit sound emulation only for 3,5" 300 rpm drives, until we have sound samples for other rpm drives
// 7. Volume control for drive sounds
// 8. Configuration option to enable/disable drive sounds
/* Audio sample structure */
typedef struct {
const char *filename;
int16_t *buffer;
int samples;
} audio_sample_t;
/* Single step audio state */
typedef struct {
int position;
int active;
} single_step_state_t;
/* Multi-track seek audio state */
typedef struct {
int position;
int active;
int duration_samples;
int from_track;
int to_track;
} multi_seek_state_t;
/* Static audio sample definitions */
static audio_sample_t spindlemotor_start = {
.filename = "mitsumi_spindle_motor_start_48000_16_1_PCM.wav",
.buffer = NULL,
.samples = 0
};
static audio_sample_t spindlemotor_loop = {
.filename = "mitsumi_spindle_motor_loop_48000_16_1_PCM.wav",
.buffer = NULL,
.samples = 0
};
static audio_sample_t spindlemotor_stop = {
.filename = "mitsumi_spindle_motor_stop_48000_16_1_PCM.wav",
.buffer = NULL,
.samples = 0
};
static audio_sample_t single_track_step = {
.filename = "mitsumi_track_step_48000_16_1_PCM.wav",
.buffer = NULL,
.samples = 0
};
static audio_sample_t multi_track_seek = {
.filename = "mitsumi_seek_80_tracks_495ms_48000_16_1_PCM.wav",
.buffer = NULL,
.samples = 0
};
/* Audio state for each drive */
static int spindlemotor_pos[FDD_NUM] = {};
static motor_state_t spindlemotor_state[FDD_NUM] = {};
static float spindlemotor_fade_volume[FDD_NUM] = {};
static int spindlemotor_fade_samples_remaining[FDD_NUM] = {};
/* Single step audio state for each drive */
static single_step_state_t single_step_state[FDD_NUM] = {};
/* Multi-track seek audio state for each drive */
static multi_seek_state_t multi_seek_state[FDD_NUM] = {};
extern uint64_t motoron[FDD_NUM];
/* Forward declaration */
static int16_t *load_wav(const char *filename, int *sample_count);
const char *
fdd_audio_motor_state_name(motor_state_t state)
{
switch (state) {
case MOTOR_STATE_STOPPED:
return "STOPPED";
case MOTOR_STATE_STARTING:
return "STARTING";
case MOTOR_STATE_RUNNING:
return "RUNNING";
case MOTOR_STATE_STOPPING:
return "STOPPING";
default:
return "UNKNOWN";
}
}
static int16_t *
load_wav(const char *filename, int *sample_count)
{
FILE *f = fopen(filename, "rb");
if (!f)
return NULL;
wav_header_t hdr;
if (fread(&hdr, sizeof(hdr), 1, f) != 1) {
fclose(f);
return NULL;
}
if (memcmp(hdr.riff, "RIFF", 4) || memcmp(hdr.wave, "WAVE", 4) || memcmp(hdr.fmt, "fmt ", 4) || memcmp(hdr.data, "data", 4)) {
fclose(f);
return NULL;
}
/* Accept both mono and stereo, 16-bit PCM */
if (hdr.audio_format != 1 || hdr.bits_per_sample != 16 || (hdr.num_channels != 1 && hdr.num_channels != 2)) {
fclose(f);
return NULL;
}
int input_samples = hdr.data_size / 2; /* 2 bytes per sample */
int16_t *input_data = malloc(hdr.data_size);
if (!input_data) {
fclose(f);
return NULL;
}
if (fread(input_data, 1, hdr.data_size, f) != hdr.data_size) {
free(input_data);
fclose(f);
return NULL;
}
fclose(f);
int16_t *output_data;
int output_samples;
if (hdr.num_channels == 1) {
/* Convert mono to stereo */
output_samples = input_samples; /* Number of stereo sample pairs */
output_data = malloc(input_samples * 2 * sizeof(int16_t)); /* Allocate for stereo */
if (!output_data) {
free(input_data);
return NULL;
}
/* Convert mono to stereo by duplicating each sample */
for (int i = 0; i < input_samples; i++) {
output_data[i * 2] = input_data[i]; /* Left channel */
output_data[i * 2 + 1] = input_data[i]; /* Right channel */
}
free(input_data);
} else {
/* Already stereo */
output_data = input_data;
output_samples = input_samples / 2; /* Number of stereo sample pairs */
}
if (sample_count)
*sample_count = output_samples;
return output_data;
}
void
fdd_audio_init(void)
{
int i;
/* Load audio samples using the new structure */
spindlemotor_start.buffer = load_wav(spindlemotor_start.filename, &spindlemotor_start.samples);
spindlemotor_loop.buffer = load_wav(spindlemotor_loop.filename, &spindlemotor_loop.samples);
spindlemotor_stop.buffer = load_wav(spindlemotor_stop.filename, &spindlemotor_stop.samples);
single_track_step.buffer = load_wav(single_track_step.filename, &single_track_step.samples);
multi_track_seek.buffer = load_wav(multi_track_seek.filename, &multi_track_seek.samples);
/* Initialize audio state for all drives */
for (i = 0; i < FDD_NUM; i++) {
spindlemotor_pos[i] = 0;
spindlemotor_state[i] = MOTOR_STATE_STOPPED;
spindlemotor_fade_volume[i] = 1.0f;
spindlemotor_fade_samples_remaining[i] = 0;
/* Initialize single step state */
single_step_state[i].position = 0;
single_step_state[i].active = 0;
/* Initialize multi-track seek state */
multi_seek_state[i].position = 0;
multi_seek_state[i].active = 0;
multi_seek_state[i].duration_samples = 0;
multi_seek_state[i].from_track = -1;
multi_seek_state[i].to_track = -1;
}
/* Initialize sound thread */
sound_fdd_thread_init();
}
void
fdd_audio_close(void)
{
if (spindlemotor_start.buffer) {
free(spindlemotor_start.buffer);
spindlemotor_start.buffer = NULL;
spindlemotor_start.samples = 0;
}
if (spindlemotor_loop.buffer) {
free(spindlemotor_loop.buffer);
spindlemotor_loop.buffer = NULL;
spindlemotor_loop.samples = 0;
}
if (spindlemotor_stop.buffer) {
free(spindlemotor_stop.buffer);
spindlemotor_stop.buffer = NULL;
spindlemotor_stop.samples = 0;
}
if (single_track_step.buffer) {
free(single_track_step.buffer);
single_track_step.buffer = NULL;
single_track_step.samples = 0;
}
if (multi_track_seek.buffer) {
free(multi_track_seek.buffer);
multi_track_seek.buffer = NULL;
multi_track_seek.samples = 0;
}
/* End sound thread */
sound_fdd_thread_end();
}
void
fdd_audio_set_motor_enable(int drive, int motor_enable)
{
if (motor_enable && !motoron[drive]) {
/* Motor starting up */
if (spindlemotor_state[drive] == MOTOR_STATE_STOPPING) {
/* Interrupt stop sequence and transition back to loop */
spindlemotor_state[drive] = MOTOR_STATE_RUNNING;
spindlemotor_pos[drive] = 0;
spindlemotor_fade_volume[drive] = 1.0f;
spindlemotor_fade_samples_remaining[drive] = 0;
} else {
/* Normal startup */
spindlemotor_state[drive] = MOTOR_STATE_STARTING;
spindlemotor_pos[drive] = 0;
spindlemotor_fade_volume[drive] = 1.0f;
spindlemotor_fade_samples_remaining[drive] = 0;
}
} else if (!motor_enable && motoron[drive]) {
/* Motor stopping */
spindlemotor_state[drive] = MOTOR_STATE_STOPPING;
spindlemotor_pos[drive] = 0;
spindlemotor_fade_volume[drive] = 1.0f;
spindlemotor_fade_samples_remaining[drive] = FADE_SAMPLES;
}
}
void
fdd_audio_play_single_track_step(int drive, int from_track, int to_track)
{
if (drive < 0 || drive >= FDD_NUM)
return;
if (abs(from_track - to_track) != 1)
return; /* Only single track movements */
single_step_state[drive].position = 0;
single_step_state[drive].active = 1;
}
void
fdd_audio_play_multi_track_seek(int drive, int from_track, int to_track)
{
if (drive < 0 || drive >= FDD_NUM)
return;
int track_diff = abs(from_track - to_track);
if (track_diff <= 1)
return; /* Use single step for 1 track movements */
if (!multi_track_seek.buffer || multi_track_seek.samples == 0)
return; /* No multi-track seek sample loaded */
/* Check if a seek is already active */
if (multi_seek_state[drive].active &&
multi_seek_state[drive].from_track == from_track &&
multi_seek_state[drive].to_track == to_track) {
return;
}
/* Calculate duration: 495ms for 80 tracks = 6.1875ms per track at 48kHz sample rate */
/* 6.1875ms = 0.0061875s, at 48000 Hz = 297 samples per track */
int duration_samples = track_diff * 297; /* 6.1875ms * track_diff * 48kHz */
/* Clamp to maximum available sample length */
if (duration_samples > multi_track_seek.samples)
duration_samples = multi_track_seek.samples;
/* Start new seek (or restart interrupted seek) */
multi_seek_state[drive].position = 0;
multi_seek_state[drive].active = 1;
multi_seek_state[drive].duration_samples = duration_samples;
multi_seek_state[drive].from_track = from_track;
multi_seek_state[drive].to_track = to_track;
}
void
fdd_audio_callback(int16_t *buffer, int length)
{
/* Clear buffer */
memset(buffer, 0, length * sizeof(int16_t));
/* Check if any motor is running or transitioning, or any audio is active */
int any_audio_active = 0;
for (int drive = 0; drive < FDD_NUM; drive++) {
if (spindlemotor_state[drive] != MOTOR_STATE_STOPPED ||
single_step_state[drive].active ||
multi_seek_state[drive].active) {
any_audio_active = 1;
break;
}
}
if (!any_audio_active)
return;
float *float_buffer = (float *) buffer;
int samples_in_buffer = length / 2;
/* Process audio for all drives */
for (int drive = 0; drive < FDD_NUM; drive++) {
for (int i = 0; i < samples_in_buffer; i++) {
float left_sample = 0.0f;
float right_sample = 0.0f;
/* Process motor audio */
if (spindlemotor_state[drive] != MOTOR_STATE_STOPPED) {
switch (spindlemotor_state[drive]) {
case MOTOR_STATE_STARTING:
if (spindlemotor_start.buffer && spindlemotor_pos[drive] < spindlemotor_start.samples) {
/* Play start sound */
left_sample = (float) spindlemotor_start.buffer[spindlemotor_pos[drive] * 2] / 32768.0f;
right_sample = (float) spindlemotor_start.buffer[spindlemotor_pos[drive] * 2 + 1] / 32768.0f;
spindlemotor_pos[drive]++;
} else {
/* Start sound finished, transition to loop */
spindlemotor_state[drive] = MOTOR_STATE_RUNNING;
spindlemotor_pos[drive] = 0;
}
break;
case MOTOR_STATE_RUNNING:
if (spindlemotor_loop.buffer && spindlemotor_loop.samples > 0) {
/* Play loop sound */
left_sample = (float) spindlemotor_loop.buffer[spindlemotor_pos[drive] * 2] / 32768.0f;
right_sample = (float) spindlemotor_loop.buffer[spindlemotor_pos[drive] * 2 + 1] / 32768.0f;
spindlemotor_pos[drive]++;
/* Loop back to beginning */
if (spindlemotor_pos[drive] >= spindlemotor_loop.samples) {
spindlemotor_pos[drive] = 0;
}
}
break;
case MOTOR_STATE_STOPPING:
if (spindlemotor_fade_samples_remaining[drive] > 0) {
/* Mix fading loop sound with rising stop sound */
float loop_volume = spindlemotor_fade_volume[drive];
float stop_volume = 1.0f - loop_volume;
float loop_left = 0.0f, loop_right = 0.0f;
float stop_left = 0.0f, stop_right = 0.0f;
/* Get loop sample (continue from current position) */
if (spindlemotor_loop.buffer && spindlemotor_loop.samples > 0) {
int loop_pos = spindlemotor_pos[drive] % spindlemotor_loop.samples;
loop_left = (float) spindlemotor_loop.buffer[loop_pos * 2] / 32768.0f;
loop_right = (float) spindlemotor_loop.buffer[loop_pos * 2 + 1] / 32768.0f;
}
/* Get stop sample */
if (spindlemotor_stop.buffer && spindlemotor_pos[drive] < spindlemotor_stop.samples) {
stop_left = (float) spindlemotor_stop.buffer[spindlemotor_pos[drive] * 2] / 32768.0f;
stop_right = (float) spindlemotor_stop.buffer[spindlemotor_pos[drive] * 2 + 1] / 32768.0f;
}
/* Mix the sounds */
left_sample = loop_left * loop_volume + stop_left * stop_volume;
right_sample = loop_right * loop_volume + stop_right * stop_volume;
spindlemotor_pos[drive]++;
spindlemotor_fade_samples_remaining[drive]--;
/* Update fade volume */
spindlemotor_fade_volume[drive] = (float) spindlemotor_fade_samples_remaining[drive] / FADE_SAMPLES;
} else {
/* Fade completed, play remaining stop sound */
if (spindlemotor_stop.buffer && spindlemotor_pos[drive] < spindlemotor_stop.samples) {
left_sample = (float) spindlemotor_stop.buffer[spindlemotor_pos[drive] * 2] / 32768.0f;
right_sample = (float) spindlemotor_stop.buffer[spindlemotor_pos[drive] * 2 + 1] / 32768.0f;
spindlemotor_pos[drive]++;
} else {
/* Stop sound finished */
spindlemotor_state[drive] = MOTOR_STATE_STOPPED;
/* Note: Timer disabling is handled by fdd.c, not here */
}
}
break;
default:
break;
}
}
/* Process single step audio */
if (single_step_state[drive].active) {
if (single_track_step.buffer && single_step_state[drive].position < single_track_step.samples) {
/* Mix step sound with motor sound */
float step_left = (float) single_track_step.buffer[single_step_state[drive].position * 2] / 32768.0f;
float step_right = (float) single_track_step.buffer[single_step_state[drive].position * 2 + 1] / 32768.0f;
left_sample += step_left;
right_sample += step_right;
single_step_state[drive].position++;
} else {
/* Step sound finished */
single_step_state[drive].active = 0;
single_step_state[drive].position = 0;
}
}
/* Process multi-track seek audio */
if (multi_seek_state[drive].active) {
if (multi_track_seek.buffer &&
multi_seek_state[drive].position < multi_seek_state[drive].duration_samples &&
multi_seek_state[drive].position < multi_track_seek.samples) {
/* Mix seek sound with motor sound */
float seek_left = (float) multi_track_seek.buffer[multi_seek_state[drive].position * 2] / 32768.0f;
float seek_right = (float) multi_track_seek.buffer[multi_seek_state[drive].position * 2 + 1] / 32768.0f;
left_sample += seek_left;
right_sample += seek_right;
multi_seek_state[drive].position++;
} else {
/* Seek sound finished */
multi_seek_state[drive].active = 0;
multi_seek_state[drive].position = 0;
multi_seek_state[drive].duration_samples = 0;
multi_seek_state[drive].from_track = -1;
multi_seek_state[drive].to_track = -1;
}
}
/* Mix this drive's audio into the buffer */
float_buffer[i * 2] += left_sample;
float_buffer[i * 2 + 1] += right_sample;
}
}
}

View File

@@ -0,0 +1,76 @@
/*
* 86Box A hypervisor and IBM PC system emulator that specializes in
* running old operating systems and software designed for IBM
* PC systems and compatibles from 1981 through fairly recent
* system designs based on the PCI bus.
*
* This file is part of the 86Box distribution.
*
* Definitions for the floppy drive audio emulation.
*
* Authors: Toni Riikonen, <riikonen.toni@gmail.com>
*
* Copyright 2025 Toni Riikonen.
*/
#ifndef EMU_FDD_AUDIO_H
#define EMU_FDD_AUDIO_H
#include <stdint.h>
#ifdef __cplusplus
extern "C" {
#endif
/* Motor sound states */
typedef enum {
MOTOR_STATE_STOPPED = 0,
MOTOR_STATE_STARTING,
MOTOR_STATE_RUNNING,
MOTOR_STATE_STOPPING
} motor_state_t;
/* WAV header structure */
typedef struct {
char riff[4];
uint32_t size;
char wave[4];
char fmt[4];
uint32_t fmt_size;
uint16_t audio_format;
uint16_t num_channels;
uint32_t sample_rate;
uint32_t byte_rate;
uint16_t block_align;
uint16_t bits_per_sample;
char data[4];
uint32_t data_size;
} wav_header_t;
/* Fade duration: 75ms at 48kHz = 3600 samples */
#define FADE_DURATION_MS 75
#define FADE_SAMPLES (48000 * FADE_DURATION_MS / 1000)
/* FDD audio initialization and cleanup */
extern void fdd_audio_init(void);
extern void fdd_audio_close(void);
/* Motor control for audio */
extern void fdd_audio_set_motor_enable(int drive, int motor_enable);
/* Single sector movement audio */
extern void fdd_audio_play_single_track_step(int drive, int from_track, int to_track);
/* Multi-track seek audio */
extern void fdd_audio_play_multi_track_seek(int drive, int from_track, int to_track);
/* Audio callback function */
extern void fdd_audio_callback(int16_t *buffer, int length);
/* State name helper function */
extern const char *fdd_audio_motor_state_name(motor_state_t state);
#ifdef __cplusplus
}
#endif
#endif /*EMU_FDD_AUDIO_H*/

View File

@@ -103,12 +103,16 @@ extern void sound_card_reset(void);
extern void sound_cd_thread_end(void);
extern void sound_cd_thread_reset(void);
extern void sound_fdd_thread_init(void);
extern void sound_fdd_thread_end(void);
extern void closeal(void);
extern void inital(void);
extern void givealbuffer(const void *buf);
extern void givealbuffer_music(const void *buf);
extern void givealbuffer_wt(const void *buf);
extern void givealbuffer_cd(const void *buf);
extern void givealbuffer_fdd(const void *buf, const uint32_t size);
#define sb_vibra16c_onboard_relocate_base sb_vibra16s_onboard_relocate_base
#define sb_vibra16cl_onboard_relocate_base sb_vibra16s_onboard_relocate_base

View File

@@ -0,0 +1 @@
{"requests":[{"kind":"cache","version":2},{"kind":"cmakeFiles","version":1},{"kind":"codemodel","version":2},{"kind":"toolchains","version":1}]}

View File

@@ -0,0 +1 @@
msvc_x64_x64

View File

@@ -38,14 +38,15 @@
#define I_WT 2
#define I_CD 3
#define I_MIDI 4
#define I_FDD 5
static int audio[5] = {-1, -1, -1, -1, -1};
static int audio[6] = {-1, -1, -1, -1, -1, -1};
#ifdef USE_NEW_API
static struct audio_swpar info[5];
#else
static audio_info_t info[5];
static audio_info_t info[6];
#endif
static int freqs[5] = {SOUND_FREQ, MUSIC_FREQ, WT_FREQ, CD_FREQ, 0};
static int freqs[6] = {SOUND_FREQ, MUSIC_FREQ, WT_FREQ, CD_FREQ, SOUND_FREQ, 0};
void closeal(void){
int i;
@@ -152,6 +153,11 @@ void givealbuffer_wt(const void *buf){
void givealbuffer_cd(const void *buf){
givealbuffer_common(buf, I_CD, CD_BUFLEN << 1);
}
void givealbuffer_fdd(const void *buf, const uint32_t size){
givealbuffer_common(buf, I_FDD, (int) size);
}
void givealbuffer_midi(const void *buf, const uint32_t size){
givealbuffer_common(buf, I_MIDI, (int) size);
}

View File

@@ -41,8 +41,9 @@ ALuint buffers[4]; /* front and back buffers */
ALuint buffers_music[4]; /* front and back buffers */
ALuint buffers_wt[4]; /* front and back buffers */
ALuint buffers_cd[4]; /* front and back buffers */
ALuint buffers_fdd[4]; /* front and back buffers */
ALuint buffers_midi[4]; /* front and back buffers */
static ALuint source[5]; /* audio source */
static ALuint source[6]; /* audio source - CHANGED FROM 5 TO 6 */
static int midi_freq = 44100;
static int midi_buf_size = 4410;
@@ -99,8 +100,9 @@ closeal(void)
alSourceStopv(sources, source);
alDeleteSources(sources, source);
if (sources == 4)
if (sources >= 6)
alDeleteBuffers(4, buffers_midi);
alDeleteBuffers(4, buffers_fdd);
alDeleteBuffers(4, buffers_cd);
alDeleteBuffers(4, buffers_music);
alDeleteBuffers(4, buffers);
@@ -118,13 +120,15 @@ inital(void)
float *wt_buf = NULL;
float *cd_buf = NULL;
float *midi_buf = NULL;
float *fdd_buf = NULL;
int16_t *buf_int16 = NULL;
int16_t *music_buf_int16 = NULL;
int16_t *wt_buf_int16 = NULL;
int16_t *cd_buf_int16 = NULL;
int16_t *midi_buf_int16 = NULL;
int16_t *fdd_buf_int16 = NULL;
int init_midi = 0;
int init_midi = 0;
if (initialized)
return;
@@ -136,13 +140,14 @@ inital(void)
if ((strcmp(mdn, "none") != 0) && (strcmp(mdn, SYSTEM_MIDI_INTERNAL_NAME) != 0))
init_midi = 1; /* If the device is neither none, nor system MIDI, initialize the
MIDI buffer and source, otherwise, do not. */
sources = 4 + !!init_midi;
sources = 5 + !!init_midi;
if (sound_is_float) {
buf = (float *) calloc((BUFLEN << 1), sizeof(float));
music_buf = (float *) calloc((MUSICBUFLEN << 1), sizeof(float));
wt_buf = (float *) calloc((WTBUFLEN << 1), sizeof(float));
cd_buf = (float *) calloc((CD_BUFLEN << 1), sizeof(float));
fdd_buf = (float *) calloc((BUFLEN << 1), sizeof(float));
if (init_midi)
midi_buf = (float *) calloc(midi_buf_size, sizeof(float));
} else {
@@ -150,48 +155,29 @@ inital(void)
music_buf_int16 = (int16_t *) calloc((MUSICBUFLEN << 1), sizeof(int16_t));
wt_buf_int16 = (int16_t *) calloc((WTBUFLEN << 1), sizeof(int16_t));
cd_buf_int16 = (int16_t *) calloc((CD_BUFLEN << 1), sizeof(int16_t));
fdd_buf_int16 = (int16_t *) calloc((BUFLEN << 1), sizeof(int16_t));
if (init_midi)
midi_buf_int16 = (int16_t *) calloc(midi_buf_size, sizeof(int16_t));
}
alGenBuffers(4, buffers);
alGenBuffers(4, buffers_cd);
alGenBuffers(4, buffers_fdd);
alGenBuffers(4, buffers_music);
alGenBuffers(4, buffers_wt);
if (init_midi)
alGenBuffers(4, buffers_midi);
if (init_midi)
alGenSources(5, source);
else
alGenSources(4, source);
// Create sources: 0=main, 1=music, 2=wt, 3=cd, 4=fdd, 5=midi(optional)
alGenSources(sources, source);
alSource3f(source[0], AL_POSITION, 0.0f, 0.0f, 0.0f);
alSource3f(source[0], AL_VELOCITY, 0.0f, 0.0f, 0.0f);
alSource3f(source[0], AL_DIRECTION, 0.0f, 0.0f, 0.0f);
alSourcef(source[0], AL_ROLLOFF_FACTOR, 0.0f);
alSourcei(source[0], AL_SOURCE_RELATIVE, AL_TRUE);
alSource3f(source[1], AL_POSITION, 0.0f, 0.0f, 0.0f);
alSource3f(source[1], AL_VELOCITY, 0.0f, 0.0f, 0.0f);
alSource3f(source[1], AL_DIRECTION, 0.0f, 0.0f, 0.0f);
alSourcef(source[1], AL_ROLLOFF_FACTOR, 0.0f);
alSourcei(source[1], AL_SOURCE_RELATIVE, AL_TRUE);
alSource3f(source[2], AL_POSITION, 0.0f, 0.0f, 0.0f);
alSource3f(source[2], AL_VELOCITY, 0.0f, 0.0f, 0.0f);
alSource3f(source[2], AL_DIRECTION, 0.0f, 0.0f, 0.0f);
alSourcef(source[2], AL_ROLLOFF_FACTOR, 0.0f);
alSourcei(source[2], AL_SOURCE_RELATIVE, AL_TRUE);
alSource3f(source[3], AL_POSITION, 0.0f, 0.0f, 0.0f);
alSource3f(source[3], AL_VELOCITY, 0.0f, 0.0f, 0.0f);
alSource3f(source[3], AL_DIRECTION, 0.0f, 0.0f, 0.0f);
alSourcef(source[3], AL_ROLLOFF_FACTOR, 0.0f);
alSourcei(source[3], AL_SOURCE_RELATIVE, AL_TRUE);
if (init_midi) {
alSource3f(source[4], AL_POSITION, 0.0f, 0.0f, 0.0f);
alSource3f(source[4], AL_VELOCITY, 0.0f, 0.0f, 0.0f);
alSource3f(source[4], AL_DIRECTION, 0.0f, 0.0f, 0.0f);
alSourcef(source[4], AL_ROLLOFF_FACTOR, 0.0f);
alSourcei(source[4], AL_SOURCE_RELATIVE, AL_TRUE);
// Initialize all sources
for (int i = 0; i < sources; i++) {
alSource3f(source[i], AL_POSITION, 0.0f, 0.0f, 0.0f);
alSource3f(source[i], AL_VELOCITY, 0.0f, 0.0f, 0.0f);
alSource3f(source[i], AL_DIRECTION, 0.0f, 0.0f, 0.0f);
alSourcef(source[i], AL_ROLLOFF_FACTOR, 0.0f);
alSourcei(source[i], AL_SOURCE_RELATIVE, AL_TRUE);
}
if (sound_is_float) {
@@ -199,6 +185,7 @@ inital(void)
memset(cd_buf, 0, CD_BUFLEN * 2 * sizeof(float));
memset(music_buf, 0, MUSICBUFLEN * 2 * sizeof(float));
memset(wt_buf, 0, WTBUFLEN * 2 * sizeof(float));
memset(fdd_buf, 0, BUFLEN * 2 * sizeof(float));
if (init_midi)
memset(midi_buf, 0, midi_buf_size * sizeof(float));
} else {
@@ -206,6 +193,7 @@ inital(void)
memset(cd_buf_int16, 0, CD_BUFLEN * 2 * sizeof(int16_t));
memset(music_buf_int16, 0, MUSICBUFLEN * 2 * sizeof(int16_t));
memset(wt_buf_int16, 0, WTBUFLEN * 2 * sizeof(int16_t));
memset(fdd_buf_int16, 0, BUFLEN * 2 * sizeof(int16_t));
if (init_midi)
memset(midi_buf_int16, 0, midi_buf_size * sizeof(int16_t));
}
@@ -216,6 +204,7 @@ inital(void)
alBufferData(buffers_music[c], AL_FORMAT_STEREO_FLOAT32, music_buf, MUSICBUFLEN * 2 * sizeof(float), MUSIC_FREQ);
alBufferData(buffers_wt[c], AL_FORMAT_STEREO_FLOAT32, wt_buf, WTBUFLEN * 2 * sizeof(float), WT_FREQ);
alBufferData(buffers_cd[c], AL_FORMAT_STEREO_FLOAT32, cd_buf, CD_BUFLEN * 2 * sizeof(float), CD_FREQ);
alBufferData(buffers_fdd[c], AL_FORMAT_STEREO_FLOAT32, fdd_buf, BUFLEN * 2 * sizeof(float), FREQ);
if (init_midi)
alBufferData(buffers_midi[c], AL_FORMAT_STEREO_FLOAT32, midi_buf, midi_buf_size * (int) sizeof(float), midi_freq);
} else {
@@ -223,6 +212,7 @@ inital(void)
alBufferData(buffers_music[c], AL_FORMAT_STEREO16, music_buf_int16, MUSICBUFLEN * 2 * sizeof(int16_t), MUSIC_FREQ);
alBufferData(buffers_wt[c], AL_FORMAT_STEREO16, wt_buf_int16, WTBUFLEN * 2 * sizeof(int16_t), WT_FREQ);
alBufferData(buffers_cd[c], AL_FORMAT_STEREO16, cd_buf_int16, CD_BUFLEN * 2 * sizeof(int16_t), CD_FREQ);
alBufferData(buffers_fdd[c], AL_FORMAT_STEREO16, fdd_buf_int16, BUFLEN * 2 * sizeof(int16_t), FREQ);
if (init_midi)
alBufferData(buffers_midi[c], AL_FORMAT_STEREO16, midi_buf_int16, midi_buf_size * (int) sizeof(int16_t), midi_freq);
}
@@ -232,14 +222,17 @@ inital(void)
alSourceQueueBuffers(source[1], 4, buffers_music);
alSourceQueueBuffers(source[2], 4, buffers_wt);
alSourceQueueBuffers(source[3], 4, buffers_cd);
alSourceQueueBuffers(source[4], 4, buffers_fdd);
if (init_midi)
alSourceQueueBuffers(source[4], 4, buffers_midi);
alSourceQueueBuffers(source[5], 4, buffers_midi);
alSourcePlay(source[0]);
alSourcePlay(source[1]);
alSourcePlay(source[2]);
alSourcePlay(source[3]);
alSourcePlay(source[4]);
if (init_midi)
alSourcePlay(source[4]);
alSourcePlay(source[5]);
if (sound_is_float) {
if (init_midi)
@@ -248,6 +241,7 @@ inital(void)
free(wt_buf);
free(music_buf);
free(buf);
free(fdd_buf);
} else {
if (init_midi)
free(midi_buf_int16);
@@ -255,6 +249,7 @@ inital(void)
free(wt_buf_int16);
free(music_buf_int16);
free(buf_int16);
free(fdd_buf_int16);
}
initialized = 1;
@@ -319,5 +314,11 @@ givealbuffer_cd(const void *buf)
void
givealbuffer_midi(const void *buf, const uint32_t size)
{
givealbuffer_common(buf, 4, (int) size, midi_freq);
givealbuffer_common(buf, 5, (int) size, midi_freq);
}
void
givealbuffer_fdd(const void *buf, const uint32_t size)
{
givealbuffer_common(buf, 4, (int) size, FREQ);
}

View File

@@ -19,7 +19,6 @@
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <sndio.h>
#include <86box/86box.h>
@@ -31,10 +30,11 @@
#define I_WT 2
#define I_CD 3
#define I_MIDI 4
#define I_FDD 5
static struct sio_hdl* audio[5] = {NULL, NULL, NULL, NULL, NULL};
static struct sio_par info[5];
static int freqs[5] = {SOUND_FREQ, MUSIC_FREQ, WT_FREQ, CD_FREQ, 0};
static struct sio_hdl* audio[6] = {NULL, NULL, NULL, NULL, NULL, NULL};
static struct sio_par info[6];
static int freqs[6] = { SOUND_FREQ, MUSIC_FREQ, WT_FREQ, CD_FREQ, SOUND_FREQ, 0 };
void closeal(void){
int i;
@@ -131,9 +131,14 @@ void givealbuffer_wt(const void *buf){
void givealbuffer_cd(const void *buf){
givealbuffer_common(buf, I_CD, CD_BUFLEN << 1);
}
void givealbuffer_midi(const void *buf, const uint32_t size){
givealbuffer_common(buf, I_MIDI, (int) size);
}
void givealbuffer_fdd(const void *buf, const uint32_t size) {
givealbuffer_common(buf, I_FDD, (int) size);
}
void al_set_midi(const int freq, UNUSED(const int buf_size)){
freqs[I_MIDI] = freq;

View File

@@ -38,6 +38,7 @@
#include <86box/timer.h>
#include <86box/snd_mpu401.h>
#include <86box/sound.h>
#include <86box/fdd_audio.h>
typedef struct {
const device_t *device;
@@ -55,7 +56,6 @@ int wavetable_pos_global = 0;
int sound_gain = 0;
static sound_handler_t sound_handlers[8];
static sound_handler_t music_handlers[8];
static sound_handler_t wavetable_handlers[8];
@@ -92,6 +92,13 @@ static int cd_buf_update = CD_BUFLEN / SOUNDBUFLEN;
static volatile int cdaudioon = 0;
static int cd_thread_enable = 0;
static thread_t *sound_fdd_thread_h;
static event_t *sound_fdd_event;
static event_t *sound_fdd_start_event;
static int16_t fdd_out_buffer[SOUNDBUFLEN * 2];
static volatile int fddaudioon = 0;
static int fdd_thread_enable = 0;
static void (*filter_cd_audio)(int channel, double *buffer, void *priv) = NULL;
static void *filter_cd_audio_p = NULL;
@@ -595,6 +602,9 @@ sound_poll(UNUSED(void *priv))
}
}
if (fdd_thread_enable) {
thread_set_event(sound_fdd_event);
}
sound_pos_global = 0;
}
}
@@ -696,17 +706,14 @@ sound_reset(void)
inital();
timer_add(&sound_poll_timer, sound_poll, NULL, 1);
sound_handlers_num = 0;
memset(sound_handlers, 0x00, 8 * sizeof(sound_handler_t));
timer_add(&music_poll_timer, music_poll, NULL, 1);
music_handlers_num = 0;
memset(music_handlers, 0x00, 8 * sizeof(sound_handler_t));
timer_add(&wavetable_poll_timer, wavetable_poll, NULL, 1);
wavetable_handlers_num = 0;
memset(wavetable_handlers, 0x00, 8 * sizeof(sound_handler_t));
@@ -783,3 +790,67 @@ sound_cd_thread_reset(void)
cd_thread_enable = available_cdrom_drives ? 1 : 0;
}
static void
sound_fdd_clean_buffers(void)
{
memset(fdd_out_buffer, 0, SOUNDBUFLEN * 2);
}
static void
sound_fdd_thread(UNUSED(void *param))
{
thread_set_event(sound_fdd_start_event);
while (fddaudioon) {
thread_wait_event(sound_fdd_event, -1);
thread_reset_event(sound_fdd_event);
if (!fddaudioon)
break;
static float fdd_float_buffer[SOUNDBUFLEN * 2];
memset(fdd_float_buffer, 0, sizeof(fdd_float_buffer));
fdd_audio_callback((int16_t*)fdd_float_buffer, SOUNDBUFLEN * 2);
givealbuffer_fdd(fdd_float_buffer, SOUNDBUFLEN * 2);
}
}
void
sound_fdd_thread_init(void)
{
if (!fddaudioon) {
fddaudioon = 1;
fdd_thread_enable = 1;
sound_fdd_start_event = thread_create_event();
sound_fdd_event = thread_create_event();
sound_fdd_thread_h = thread_create(sound_fdd_thread, NULL);
thread_wait_event(sound_fdd_start_event, -1);
thread_reset_event(sound_fdd_start_event);
}
}
void
sound_fdd_thread_end(void)
{
if (fddaudioon) {
fddaudioon = 0;
fdd_thread_enable = 0;
thread_set_event(sound_fdd_event);
thread_wait(sound_fdd_thread_h);
if (sound_fdd_event) {
thread_destroy_event(sound_fdd_event);
sound_fdd_event = NULL;
}
sound_fdd_thread_h = NULL;
if (sound_fdd_start_event) {
thread_destroy_event(sound_fdd_start_event);
sound_fdd_start_event = NULL;
}
}
}

View File

@@ -55,6 +55,7 @@ static IXAudio2SourceVoice *srcvoicemusic = NULL;
static IXAudio2SourceVoice *srcvoicewt = NULL;
static IXAudio2SourceVoice *srcvoicemidi = NULL;
static IXAudio2SourceVoice *srcvoicecd = NULL;
static IXAudio2SourceVoice *srcvoicefdd = NULL;
#define FREQ SOUND_FREQ
#define BUFLEN SOUNDBUFLEN
@@ -184,11 +185,18 @@ inital(void)
(void) IXAudio2_CreateSourceVoice(xaudio2, &srcvoicecd, &fmt, 0, 2.0f, &callbacks, NULL, NULL);
fmt.nSamplesPerSec = FREQ;
fmt.nBlockAlign = fmt.nChannels * fmt.wBitsPerSample / 8;
fmt.nAvgBytesPerSec = fmt.nSamplesPerSec * fmt.nBlockAlign;
(void) IXAudio2_CreateSourceVoice(xaudio2, &srcvoicefdd, &fmt, 0, 2.0f, &callbacks, NULL, NULL);
(void) IXAudio2SourceVoice_SetVolume(srcvoice, 1, XAUDIO2_COMMIT_NOW);
(void) IXAudio2SourceVoice_Start(srcvoice, 0, XAUDIO2_COMMIT_NOW);
(void) IXAudio2SourceVoice_Start(srcvoicecd, 0, XAUDIO2_COMMIT_NOW);
(void) IXAudio2SourceVoice_Start(srcvoicemusic, 0, XAUDIO2_COMMIT_NOW);
(void) IXAudio2SourceVoice_Start(srcvoicewt, 0, XAUDIO2_COMMIT_NOW);
(void) IXAudio2SourceVoice_Start(srcvoicefdd, 0, XAUDIO2_COMMIT_NOW);
const char *mdn = midi_out_device_get_internal_name(midi_output_device_current);
@@ -218,6 +226,8 @@ closeal(void)
(void) IXAudio2SourceVoice_FlushSourceBuffers(srcvoicewt);
(void) IXAudio2SourceVoice_Stop(srcvoicecd, 0, XAUDIO2_COMMIT_NOW);
(void) IXAudio2SourceVoice_FlushSourceBuffers(srcvoicecd);
(void) IXAudio2SourceVoice_Stop(srcvoicefdd, 0, XAUDIO2_COMMIT_NOW);
(void) IXAudio2SourceVoice_FlushSourceBuffers(srcvoicefdd);
if (srcvoicemidi) {
(void) IXAudio2SourceVoice_Stop(srcvoicemidi, 0, XAUDIO2_COMMIT_NOW);
(void) IXAudio2SourceVoice_FlushSourceBuffers(srcvoicemidi);
@@ -225,13 +235,14 @@ closeal(void)
}
IXAudio2SourceVoice_DestroyVoice(srcvoicewt);
IXAudio2SourceVoice_DestroyVoice(srcvoicecd);
IXAudio2SourceVoice_DestroyVoice(srcvoicefdd);
IXAudio2SourceVoice_DestroyVoice(srcvoicemusic);
IXAudio2SourceVoice_DestroyVoice(srcvoice);
IXAudio2MasteringVoice_DestroyVoice(mastervoice);
IXAudio2_Release(xaudio2);
srcvoice = srcvoicecd = srcvoicemidi = NULL;
mastervoice = NULL;
xaudio2 = NULL;
srcvoice = srcvoicecd = srcvoicemidi = srcvoicefdd = NULL;
mastervoice = NULL;
xaudio2 = NULL;
#if defined(_WIN32) && !defined(USE_FAUDIO)
dynld_close(xaudio2_handle);
@@ -291,6 +302,18 @@ givealbuffer_cd(const void *buf)
givealbuffer_common(buf, srcvoicecd, CD_BUFLEN << 1);
}
void
givealbuffer_fdd(const void *buf, const uint32_t size)
{
if (!initialized)
return;
if (!srcvoicefdd)
return;
givealbuffer_common(buf, srcvoicefdd, size);
}
void
al_set_midi(const int freq, const int buf_size)
{
@@ -324,4 +347,4 @@ void
givealbuffer_midi(const void *buf, const uint32_t size)
{
givealbuffer_common(buf, srcvoicemidi, size);
}
}