-
Notifications
You must be signed in to change notification settings - Fork 4
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Added Windy Fairy's Konami System 573 digital audio offset plugin.
- Loading branch information
Showing
7 changed files
with
283 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
* text=auto !eol | ||
|
||
*.json svneol=native#application/json | ||
*.lua svneol=native#text/plain | ||
*.md svneol=native#text/plain |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,26 @@ | ||
name: Validate plugins | ||
|
||
on: | ||
push: | ||
paths: | ||
- '.github/workflows/**' | ||
- 'plugins/**' | ||
pull_request: | ||
paths: | ||
- '.github/workflows/**' | ||
- 'plugins/**' | ||
|
||
permissions: | ||
contents: read | ||
|
||
jobs: | ||
validate: | ||
runs-on: ubuntu-latest | ||
steps: | ||
- uses: actions/checkout@master | ||
- name: Install dependencies | ||
run: | | ||
sudo apt-get update | ||
sudo apt-get install -y python3-jsonschema | ||
- name: Validate plugin properties | ||
run: for x in plugins/*/plugin.json ; do jsonschema -i "$x" plugins/plugin.schema ; done |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,35 @@ | ||
# Konami System 573 digital audio offset plugin | ||
|
||
This plugin works by intercepting audio timer register reads in Konami System 573 digital hardware games and may not work perfectly in every game depending on how it uses the timer register. | ||
|
||
## Configuration | ||
|
||
Here is an example **settings.json** commented to demonstrate how to add game-specific offsets and a default offset to be used for all games on System 573 digital hardware without a specific offset specified. | ||
|
||
A default offset of 28 ms is what I personally found to be most useful when running MAME on Windows, with the PortAudio sound output module using the WASAPI back-end for lowest audio latency. I suggest you experiment with the default offset to figure out what works best for your setup. | ||
|
||
```json | ||
{ | ||
"default": "28ms", // Specify a default offset for all System 573 digital audio games unless overridden | ||
// Setting this to 0 is the equivalent of disabling the default override | ||
// Can be specified as a number of samples (e.g. 1234) or a delay in milliseconds (e.g. 1234ms) | ||
"overrides": { | ||
"ddrmax": 1234, // Offset for the game "ddrmax" specified as a number of samples | ||
"ddr5m": "50ms", // Offset for the gaem "ddr5m" specified as a delay in milliseconds (automatically converted to a number of samples) | ||
} | ||
} | ||
``` | ||
|
||
## License | ||
|
||
Copyright © 2022-2023 windyfairy | ||
|
||
Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: | ||
|
||
1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. | ||
|
||
2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. | ||
|
||
3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. | ||
|
||
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS “AS IS” AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,168 @@ | ||
-- license:BSD-3-Clause | ||
-- copyright-holders:windyfairy | ||
local exports = { | ||
name = 'ksys573_da_offset', | ||
version = '0.0.1', | ||
description = 'Konami System 573 digital audio offset plugin', | ||
license = 'BSD-3-Clause', | ||
author = { name = 'windyfairy' } | ||
} | ||
|
||
|
||
local plugindir | ||
|
||
|
||
local function load_settings() | ||
local function calculate_offset_from_milliseconds(milliseconds) | ||
return math.floor((emu.attotime.from_msec(milliseconds):as_double() * 44100) + 0.5) | ||
end | ||
|
||
local function get_processed_offset_value(val) | ||
local match = string.match(val, "([%d]+[%.]?[%d]*)%s*[mM][sS]") | ||
if match ~= nil then | ||
return calculate_offset_from_milliseconds(tonumber(match)) | ||
end | ||
|
||
return math.floor(val + 0.5) | ||
end | ||
|
||
local json = require('json') | ||
local filename = plugindir .. '/settings.json' | ||
local file = io.open(filename, 'r') | ||
local default_offset = calculate_offset_from_milliseconds(28) | ||
|
||
local loaded_settings | ||
if file then | ||
loaded_settings = json.parse(file:read('a')) | ||
file:close() | ||
end | ||
if not loaded_settings then | ||
emu.print_error(string.format('Error loading System 573 audio offset settings: error opening or parsing %s as JSON', filename)) | ||
loaded_settings = {} | ||
end | ||
|
||
if loaded_settings['default'] == nil then | ||
loaded_settings['default'] = default_offset | ||
end | ||
loaded_settings['default'] = get_processed_offset_value(loaded_settings['default']) | ||
|
||
if loaded_settings['overrides'] == nil then | ||
loaded_settings['overrides'] = {} | ||
end | ||
|
||
for k, v in pairs(loaded_settings["overrides"]) do | ||
loaded_settings['overrides'][k] = get_processed_offset_value(v) | ||
end | ||
|
||
return loaded_settings | ||
end | ||
|
||
|
||
local ksys573_da_offset = exports | ||
|
||
function ksys573_da_offset.set_folder(path) | ||
plugindir = path | ||
end | ||
|
||
function ksys573_da_offset.startplugin() | ||
local counter_offset | ||
local passthrough_counter_high, passthrough_counter_low | ||
|
||
local function install_counter_passthrough(memory) | ||
local max = math.max | ||
local memory_read_i16 = memory.read_i16 | ||
local counter_current = 0 | ||
local is_callback_read = false | ||
|
||
local function get_offset_counter() | ||
return max(0, counter_current - counter_offset) | ||
end | ||
|
||
local function counter_high_callback(offset, data, mask) | ||
if mask == 0xffff0000 then | ||
-- hack because reading memory directly also calls the callback | ||
if is_callback_read == true then | ||
return data | ||
end | ||
|
||
return get_offset_counter() & mask | ||
end | ||
|
||
return data | ||
end | ||
|
||
local function counter_low_callback(offset, data, mask) | ||
if mask == 0x0000ffff then | ||
is_callback_read = true | ||
local counter_upper = memory_read_i16(memory, 0x1f6400ca) | ||
is_callback_read = false | ||
counter_current = (data & mask) | (counter_upper << 16) | ||
return get_offset_counter() & mask | ||
end | ||
|
||
return data | ||
end | ||
|
||
passthrough_counter_high = memory:install_read_tap(0x1f6400c8, 0x1f6400cb, "counter_high", counter_high_callback) | ||
passthrough_counter_low = memory:install_read_tap(0x1f6400cc, 0x1f6400cf, "counter_low", counter_low_callback) | ||
end | ||
|
||
local function menu_callback(index, event) | ||
return false | ||
end | ||
|
||
local function menu_populate() | ||
local menu = {} | ||
table.insert(menu, { 'System 573 Digital Audio Delay', '', 'off' }) | ||
if not counter_offset then | ||
table.insert(menu, { 'Not applicable for this system', '', 'off' }) | ||
elseif counter_offset == 0 then | ||
table.insert(menu, { 'No offset specified for this system', '', 'off' }) | ||
else | ||
table.insert(menu, { string.format('%d samples', counter_offset), '', 'off' }) | ||
end | ||
return menu | ||
end | ||
|
||
emu.register_start( | ||
function () | ||
if not manager.machine.devices[":k573dio"] then | ||
counter_offset = nil | ||
return | ||
end | ||
|
||
local settings = load_settings() | ||
counter_offset = settings['default'] | ||
|
||
local override_offset = settings['overrides'][manager.machine.system.name] | ||
if override_offset ~= nil then | ||
emu.print_verbose(string.format('System 573 audio offset override for %s found: %s -> %s', manager.machine.system.name, counter_offset, override_offset)) | ||
counter_offset = override_offset | ||
end | ||
|
||
-- don't hook the code if no offset is specified | ||
if counter_offset == 0 then | ||
return | ||
end | ||
|
||
install_counter_passthrough(manager.machine.devices[":maincpu"].spaces["program"], counter_offset) | ||
emu.print_verbose(string.format('System 573 audio counter is now being offset by %s samples.', counter_offset)) | ||
end) | ||
|
||
emu.register_stop( | ||
function () | ||
if passthrough_counter_high then | ||
passthrough_counter_high:remove() | ||
passthrough_counter_high = nil | ||
end | ||
if passthrough_counter_low then | ||
passthrough_counter_low:remove() | ||
passthrough_counter_low = nil | ||
end | ||
counter_offset = nil | ||
end) | ||
|
||
emu.register_menu(menu_callback, menu_populate, 'System 573 Digital Audio Offset') | ||
end | ||
|
||
return exports |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
{ | ||
"plugin": { | ||
"name": "ksys573_da_offset", | ||
"description": "Konami System 573 digital audio offset plugin", | ||
"version": "0.0.1", | ||
"author": "windyfairy", | ||
"type": "plugin", | ||
"start": "true" | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
{ | ||
"default": "0ms", | ||
"overrides": {} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,35 @@ | ||
{ | ||
"type": "object", | ||
"properties": { | ||
"plugin": { | ||
"type": "object", | ||
"properties": { | ||
"name": { | ||
"type": "string", | ||
"pattern": "^[A-Za-z][0-9A-Za-z_]*$" | ||
}, | ||
"description": { | ||
"type": "string" | ||
}, | ||
"version": { | ||
"type": "string" | ||
}, | ||
"author": { | ||
"type": "string" | ||
}, | ||
"type": { | ||
"type": "string", | ||
"pattern": "^(plugin|library)$" | ||
}, | ||
"start": { | ||
"type": "string", | ||
"pattern": "^(true|false)$" | ||
} | ||
}, | ||
"additionalProperties": false, | ||
"required": [ "name", "description", "version", "author", "type" ] | ||
} | ||
}, | ||
"additionalProperties": false, | ||
"required": [ "plugin" ] | ||
} |