/usr/share/openmsx/scripts/soundchip_utils.tcl is in openmsx-data 0.8.2-2.1.
This file is owned by root:root, with mode 0o644.
The actual contents of the file can be viewed below.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 | # Several utility procs for usage in other scripts
# don't export anything, just use it from the namespace,
# because these scripts aren't useful for console users
# and should therefore not be exported to the global
# namespace.
#
# These procs are specifically for sound chips.
#
# Born to prevent duplication between scripts for common stuff.
namespace eval soundchip_utils {
proc get_num_channels {soundchip} {
set num 1
while {[info exists ::${soundchip}_ch${num}_mute]} {
incr num
}
expr {$num - 1}
}
# It is advised to cache the result of this proc for each channel of each sound device
# before using it, because then a lot will be pre-evaluated and at run time only the
# actual variable stuff will be evaluated.
# We cannot cache it here, because we don't know the names of the sound chips in the
# machine you are going to use this on.
# @param soundchip the name of the soundchip as it appears in the output of
# "machine_info sounddevice"
# @channel the channel for which you want the expression to get the volume, the
# first channel is channel 0 and the channels are the ones as they are output
# by the record_channels command.
# @return expression to calculate the volume of the device for that channel in
# range [0-1]; returns just 'x' in case the chip is not supported.
# @todo:
# - frequency expressions for (some of?) the drum channels are not correct
# - implement volume for MoonSound FM (tricky stuff)
# - actually, don't use regs to calc volume but actual wave data (needs openMSX
# changes)
#
proc get_volume_expr {soundchip channel} {
switch [machine_info sounddevice $soundchip] {
"PSG" {
set regs "\"${soundchip} regs\""
return "set keybits \[debug read $regs 7\]; set val \[debug read $regs [expr {$channel + 8}]\]; expr {(\$val & 0x10) ? 1.0 : ((\$val & 0xF) / 15.0) * !((\$keybits >> $channel) & (\$keybits >> [expr {$channel + 3}]) & 1)}"
}
"MoonSound wave-part" {
set regs "\"${soundchip} regs\""
return "expr {(\[debug read $regs [expr {$channel + 0x68}]\]) ? (127 - (\[debug read $regs [expr {$channel + 0x50}]\] >> 1)) / 127.0 : 0.0}";
}
"Konami SCC" -
"Konami SCC+" {
set regs "\"${soundchip} SCC\""
return "expr {((\[debug read $regs [expr {$channel + 0xAA}]\] &0xF)) / 15.0 * ((\[debug read $regs 0xAF\] >> $channel) &1)}"
}
"MSX-MUSIC" {
set regs "\"${soundchip} regs\""
set vol_expr "(\[debug read $regs [expr {$channel + 0x30}]\] & 0x0F)"
set keyon_expr "(\[debug read $regs [expr {$channel + 0x20}]\] & 0x10)"
set music_mode_expr "$keyon_expr ? ((15 - $vol_expr) / 15.0) : 0.0"
set rhythm_expr "\[debug read $regs 0x0E\]"
if {$channel < 6} {
# always melody channel
return "expr {$music_mode_expr}"
} elseif {$channel < 9} {
# melody channel when not in rhythm mode
return "expr {($rhythm_expr & 0x20) ? 0.0 : $music_mode_expr}"
} elseif {$channel < 14} {
# rhythm channel (when rhythm mode enabled)
if {$channel < 12} {
set vol_expr "(\[debug read $regs [expr {$channel + 0x30 - 3}]\] & 0x0F)"
} else {
set vol_expr "(\[debug read $regs [expr {$channel + 0x2E - 3}]\] >> 4)"
}
switch $channel {
9 {set mask 0x30} ;# BD
10 {set mask 0x28} ;# SD
11 {set mask 0x22} ;# T-CYM
12 {set mask 0x21} ;# HH
13 {set mask 0x24} ;# TOM
}
return "expr {($rhythm_expr & $mask) ? (15 - $vol_expr) / 15.0 : 0.0}"
} else {
error "Unknown channel: $channel for $soundchip!"
}
}
"MSX-AUDIO" {
set regs "\"${soundchip} regs\""
set ofst [expr {0x43 + $channel + 5 * ($channel / 3)}]
set keyon_expr "(\[debug read $regs [expr {$channel + 0xB0}]\] & 0x20)"
set vol_expr {(63 - (\[debug read $regs $ofst\] & 63)) / 63.0}
set music_mode_expr "($keyon_expr ? [subst $vol_expr] : 0.0)"
set rhythm_expr "\[debug read $regs 0xBD\]"
if {$channel < 6} {
# always melody channel
return "expr {$music_mode_expr}"
} elseif {$channel < 9} {
# melody channel when not in rhythm mode
return "expr {($rhythm_expr & 0x20) ? 0.0 : $music_mode_expr}"
} elseif {$channel < 14} {
# rhythm channel (when rhythm mode enabled)
switch $channel {
9 {set mask 0x30; set ofst 0x53} ;# BD (slot 16)
10 {set mask 0x28; set ofst 0x54} ;# SD (slot 17)
11 {set mask 0x22; set ofst 0x55} ;# CYM (slot 18)
12 {set mask 0x21; set ofst 0x51} ;# HH (slot 13)
13 {set mask 0x24; set ofst 0x52} ;# TOM (slot 14)
}
return "expr {($rhythm_expr & $mask) ? [subst $vol_expr] : 0.0}"
} elseif {$channel < 15} {
# ADPCM
# can we output 0 when no sample is playing?
return "expr {\[debug read $regs 0x12\] / 255.0}"
} else {
error "Unknown channel: $channel for $soundchip!"
}
}
default {
return "x"
}
}
}
# It is advised to cache the result of this proc for each channel of each sound device
# before using it, because then a lot will be pre-evaluated and at run time only the
# actual variable stuff will be evaluated.
# We cannot cache it here, because we don't know the names of the sound chips in the
# machine you are going to use this on.
# @param soundchip the name of the soundchip as it appears in the output of
# "machine_info sounddevice"
# @channel the channel for which you want the expression to get the frequency, the
# first channel is channel 0 and the channels are the ones as they are output
# by the record_channels command.
# @return expression to calculate the frequency of the device for that channel in
# Hz; returns just 'x' in case the chip is not supported.
# @todo:
# - implement frequency for MoonSound
#
proc get_frequency_expr {soundchip channel} {
switch [machine_info sounddevice $soundchip] {
"PSG" {
set regs "\"${soundchip} regs\""
set basefreq [expr {3579545.454545 / 32.0}]
return "set val \[expr {\[debug read $regs \[expr {0 + ($channel * 2)}\]\] + 256 * ((\[debug read $regs \[expr {1 + ($channel * 2)}\]\]) & 15)}\]; expr {$basefreq/(\$val < 1 ? 1 : \$val)}"
}
"Konami SCC" -
"Konami SCC+" {
set regs "\"${soundchip} SCC\""
set basefreq [expr {3579545.454545 / 32.0}]
return "set val \[expr {\[debug read $regs \[expr {0xA0 + 0 + ($channel * 2)}\]\] + 256 * ((\[debug read $regs \[expr {0xA0 + 1 + ($channel * 2)}\]\]) & 15)}\]; expr {$basefreq/(\$val < 1 ? 1 : \$val)}"
}
"MSX-MUSIC" {
set regs "\"${soundchip} regs\""
set basefreq [expr {3579545.454545 / 72.0}]
set factor [expr {$basefreq / (1 << 18)}]
if {$channel >= 9} {
#drums
incr channel -3
}
return "expr {(\[debug read $regs [expr {$channel + 0x10}]\] + 256 * ((\[debug read $regs [expr {$channel + 0x20}]\]) & 1)) * $factor * (1 << (((\[debug read $regs [expr {$channel + 0x20}]\]) & 15) >> 1))}"
}
"MSX-AUDIO" {
set regs "\"${soundchip} regs\""
set basefreq [expr {3579545.454545 / 72.0}]
if {$channel == 14} { ;# ADPCM
set factor [expr {$basefreq / (1 << 16)}]
return "expr {(\[debug read $regs 0x10\] + 256 * \[debug read $regs 0x11\]) * $factor / 10}";# /10 is just to make it fall a bit into a decent range...
} else {
set factor [expr {$basefreq / (1 << 19)}]
if {$channel >= 9} {
#drums
incr channel -3
}
return "expr {(\[debug read $regs [expr {$channel + 0xA0}]\] + 256 * ((\[debug read $regs [expr {$channel + 0xB0}]\]) & 3)) * $factor * (1 << (((\[debug read $regs [expr {$channel + 0xB0}]\]) & 31) >> 2))}"
}
}
default {
return "x"
}
}
}
} ;# namespace soundchip_utils
|