Save preset data alongside other JSON settings

This commit is contained in:
StyledStrike 2024-09-30 10:46:21 -03:00
parent 510210bfe9
commit ad88b0f982
4 changed files with 205 additions and 55 deletions

View File

@ -8,6 +8,10 @@ MKeyboard = {
-- name/location of the settings file
SETTINGS_FILE = "musical_keyboard.json",
-- MIDI constants
FIRST_MIDI_CHANNEL = 0,
LAST_MIDI_CHANNEL = 15,
-- URL for the midi installation guide
URL_MIDI_GUIDE = "https://steamcommunity.com/workshop/filedetails/discussion/2656563609/3199240042192880687/"
}

View File

@ -721,7 +721,7 @@ function MKeyboard:ShowChannelsDialog()
self.frameChannels = vgui.Create( "DFrame" )
self.frameChannels:SetSize( 400, tall )
self.frameChannels:SetTitle( language.GetPhrase( "musicalk.channels" ) )
self.frameChannels:SetTitle( "#musicalk.channels" )
self.frameChannels:SetVisible( true )
self.frameChannels:SetSizable( true )
self.frameChannels:SetDraggable( true )
@ -739,28 +739,106 @@ function MKeyboard:ShowChannelsDialog()
self:OnButtonRelease( key )
end
local presetsControl = vgui.Create( "ControlPresets", self.frameChannels )
presetsControl:Dock( TOP )
presetsControl:DockMargin( 0, 0, 0, 4 )
presetsControl:SetPreset( "musical_keyboard" )
presetsControl._comboBoxes = {}
presetsControl.OnSelect = function( s, _, _, data )
for k, v in pairs( data ) do
local combo = s._comboBoxes[tonumber( k )]
-- Update the channel combo boxes with the instruments from the current preset
local channelCombos = {}
combo:ChooseOptionID( tonumber( v ) + 2 )
end
end
presetsControl.QuickSaveInternal = function( s, text )
local tabValues = {}
for i, v in ipairs( s:GetConVars() ) do
tabValues[v] = tostring( settings.channelInstruments[i - 1] or -1 )
local UpdateCombosFromCurrentPreset = function()
local preset = settings.midiChannelPresets[settings.midiCurrentPreset or ""] or {}
for channelIndex = self.FIRST_MIDI_CHANNEL, self.LAST_MIDI_CHANNEL do
local combo = channelCombos[channelIndex]
combo._isBeingModifiedByCode = true
if preset[channelIndex] then
combo:ChooseOptionID( preset[channelIndex] + 2 )
else
combo:ChooseOptionID( 1 )
end
presets.Add( s.m_strPreset, text, tabValues )
s:Update()
combo._isBeingModifiedByCode = nil
end
end
-- Channel presets list
local panelPresets = vgui.Create( "DPanel", self.frameChannels )
panelPresets:SetTall( 24 )
panelPresets:Dock( TOP )
panelPresets:DockMargin( 0, 0, 0, 2 )
local comboPresets = vgui.Create( "DComboBox", panelPresets )
comboPresets:SetSortItems( false )
comboPresets:Dock( FILL )
comboPresets.OnSelect = function( s, _, name )
if s._isBeingModifiedByCode then return end
self:SetCurrentChannelPreset( name )
self:SaveSettings()
UpdateCombosFromCurrentPreset()
end
-- Update the list of preset choices
local UpdatePresetList = function()
comboPresets:Clear()
comboPresets._isBeingModifiedByCode = true
for name, _ in SortedPairs( settings.midiChannelPresets, false ) do
comboPresets:AddChoice( name, nil, name == settings.midiCurrentPreset )
end
comboPresets._isBeingModifiedByCode = nil
end
UpdatePresetList()
local buttonDeletePreset = vgui.Create( "DImageButton", panelPresets )
buttonDeletePreset:SetWide( 22 )
buttonDeletePreset:SetTooltip( "#preset.delete" )
buttonDeletePreset:SetImage( "icon16/delete.png" )
buttonDeletePreset:SetStretchToFit( false )
buttonDeletePreset:Dock( RIGHT )
buttonDeletePreset.DoClick = function()
local name = settings.midiCurrentPreset
if name then
settings.midiChannelPresets[name] = nil
settings.midiCurrentPreset = nil
end
self:SetCurrentChannelPreset()
self:SaveSettings()
UpdatePresetList()
UpdateCombosFromCurrentPreset()
end
local buttonAddPreset = vgui.Create( "DImageButton", panelPresets )
buttonAddPreset:SetWide( 22 )
buttonAddPreset:SetTooltip( "#preset.add" )
buttonAddPreset:SetImage( "icon16/add.png" )
buttonAddPreset:SetStretchToFit( false )
buttonAddPreset:Dock( RIGHT )
buttonAddPreset.DoClick = function()
Derma_StringRequest( "#preset.saveas_title", "#preset.saveas_desc", "", function( text )
if not text or text:Trim() == "" then
presets.BadNameAlert()
return
end
self:SetMIDIChannelPreset( text, self.channelInstruments )
self:SetCurrentChannelPreset( text )
self:SaveSettings()
UpdatePresetList()
UpdateCombosFromCurrentPreset()
end )
end
-- Channels list
local scrollChannels = vgui.Create( "DScrollPanel", self.frameChannels )
scrollChannels:Dock( FILL )
@ -771,58 +849,71 @@ function MKeyboard:ShowChannelsDialog()
SetColor( 50, 50, 50, 255 )
DrawRect( 4, 4, 8, h - 8 )
self.channelState[s.channel] = Lerp( FrameTime() * 8, self.channelState[s.channel], 0 )
self.channelState[s._channelIndex] = Lerp( FrameTime() * 8, self.channelState[s._channelIndex], 0 )
SetColor( colors.automated.r, colors.automated.g, colors.automated.b, 255 * self.channelState[s.channel] )
SetColor( colors.automated.r, colors.automated.g, colors.automated.b, 255 * self.channelState[s._channelIndex] )
DrawRect( 4, 4, 8, h - 8 )
end
local function OnSelectInstrument( s, _, _, idx )
if idx == -1 then
settings.channelInstruments[s.channel] = nil
else
settings.channelInstruments[s.channel] = idx
local function OnSelectInstrument( s, _, _, instrumentIndex )
if s._isBeingModifiedByCode then return end
instrumentIndex = tonumber( instrumentIndex )
local name = settings.midiCurrentPreset or ""
local preset = settings.midiChannelPresets[name]
if not preset then
-- Create a "default" preset
name = language.GetPhrase( "musicalk.channels" )
settings.midiCurrentPreset = name
settings.midiChannelPresets[name] = {}
preset = settings.midiChannelPresets[name]
UpdatePresetList()
end
preset[s._channelIndex] = instrumentIndex
self:SetCurrentChannelPreset()
self:SaveSettings()
end
for i = 0, 15 do
self.channelState[i] = 0
for channelIndex = self.FIRST_MIDI_CHANNEL, self.LAST_MIDI_CHANNEL do
self.channelState[channelIndex] = 0
local panelChannel = vgui.Create( "DPanel", scrollChannels )
panelChannel:SetSize( wide, 32 )
panelChannel:Dock( TOP )
panelChannel:DockMargin( 0, 0, 0, 4 )
panelChannel.channel = i
panelChannel._channelIndex = channelIndex
panelChannel.Paint = PaintChannel
local labelIndex = vgui.Create( "DLabel", panelChannel )
labelIndex:SetFont( "Trebuchet24" )
labelIndex:SetTextColor( colors.white )
labelIndex:SetText( "#" .. ( i + 1 ) )
labelIndex:SetText( "##" .. channelIndex )
labelIndex:SetWide( 50 )
labelIndex:Dock( LEFT )
labelIndex:DockMargin( 20, 0, 0, 0 )
local combo = vgui.Create( "DComboBox", panelChannel )
combo:SetSortItems( false )
combo:AddChoice( language.GetPhrase( "musicalk.channels.usecurrent" ), -1, true )
combo:AddChoice( language.GetPhrase( "musicalk.channels.mute" ), 0 )
combo:AddChoice( "#musicalk.channels.usecurrent" )
combo:AddChoice( "#musicalk.channels.mute", 0 )
combo:AddSpacer()
combo:Dock( FILL )
local myInstrument = settings.channelInstruments[i] or -1
for idx, v in ipairs( self.instruments ) do
combo:AddChoice( v.name, idx, idx == myInstrument )
for i, v in ipairs( self.instruments ) do
combo:AddChoice( v.name, i )
end
combo.channel = i
combo._channelIndex = channelIndex
combo.OnSelect = OnSelectInstrument
presetsControl:AddConVar( Format( "%.2d", i ) )
presetsControl._comboBoxes[i] = combo
channelCombos[channelIndex] = combo
end
UpdateCombosFromCurrentPreset()
end

View File

@ -69,7 +69,7 @@ function MKeyboard:OnMIDIEvent( code, p1, p2 )
if cmd == "NOTE_ON" and p2 > 0 then
local channel = midi.GetCommandChannel( code )
local instrument = self.settings.channelInstruments[channel]
local instrument = self.channelInstruments[channel]
self.lastNoteWasAutomated = true
self.piano:PressNote( p1 + transpose, p2, instrument, self.colors.automated, true )

View File

@ -2,13 +2,18 @@ MKeyboard.settings = MKeyboard.settings or {
layout = 1,
instrument = 1,
sheet = 0,
velocity = 127,
transpose = 0,
midiTranspose = 0,
drawKeyLabels = true,
channelInstruments = {}
midiCurrentPreset = nil,
midiChannelPresets = {}
}
MKeyboard.channelInstruments = {}
local function ValidateInteger( n, min, max )
return math.Round( math.Clamp( tonumber( n ), min, max ) )
end
@ -21,48 +26,63 @@ function MKeyboard:LoadSettings()
local instrumentCount = #self.instruments
local settings = self.settings
-- last layout that was used on the keyboard
-- Last layout that was used on the keyboard
if data.layout then
settings.layout = ValidateInteger( data.layout, 1, #self.layouts )
end
-- last instrument that was used on the keyboard
-- Last instrument that was used on the keyboard
if data.instrument then
settings.instrument = ValidateInteger( data.instrument, 1, instrumentCount )
end
-- last selected sheet
-- Last selected sheet
if data.sheet then
settings.sheet = ValidateInteger( data.sheet, 0, #self.sheets )
end
-- last used velocity
-- Last used velocity
if data.velocity then
settings.velocity = ValidateInteger( data.velocity, 1, 127 )
end
-- last used transpose
-- Last used transpose
if data.transpose then
settings.transpose = ValidateInteger( data.transpose, -48, 48 )
end
-- last transpose that was used with midi
-- Last transpose that was used with midi
if data.midiTranspose then
settings.midiTranspose = ValidateInteger( data.midiTranspose, -48, 48 )
end
-- draw labels for keys
-- Draw labels for keys
settings.drawKeyLabels = Either( isbool( data.drawKeyLabels ), tobool( data.drawKeyLabels ), true )
-- links between instruments and MIDI channels
if data.channelInstruments and type( data.channelInstruments ) == "table" then
for c, i in pairs( data.channelInstruments ) do
local channel = ValidateInteger( c, 0, 15 )
local instrument = ValidateInteger( i, 1, instrumentCount )
-- Presets for links between MIDI channels and instruments
settings.midiChannelPresets = {}
settings.channelInstruments[channel] = instrument
if data.midiChannelPresets and type( data.midiChannelPresets ) == "table" then
for name, channelInstruments in pairs( data.midiChannelPresets ) do
if type( name ) == "string" and type( data ) == "table" then
self:SetMIDIChannelPreset( name, channelInstruments )
end
end
end
settings.midiCurrentPreset = Either( type( data.midiCurrentPreset ) == "string", data.midiCurrentPreset, nil )
if settings.midiCurrentPreset then
self:SetCurrentChannelPreset()
end
-- Create preset from a old data format
if data.channelInstruments and type( data.channelInstruments ) == "table" then
local name = language.GetPhrase( "musicalk.channels" )
self:SetMIDIChannelPreset( name, data.channelInstruments )
self:SetCurrentChannelPreset( name )
end
end
function MKeyboard:SaveSettings()
@ -74,11 +94,46 @@ function MKeyboard:SaveSettings()
layout = settings.layout,
instrument = settings.instrument,
sheet = settings.sheet,
velocity = settings.velocity,
transpose = settings.transpose,
midiTranspose = settings.midiTranspose,
channelInstruments = settings.channelInstruments,
drawKeyLabels = settings.drawKeyLabels
drawKeyLabels = settings.drawKeyLabels,
midiCurrentPreset = settings.midiCurrentPreset,
midiChannelPresets = settings.midiChannelPresets
}, true )
)
end
function MKeyboard:SetMIDIChannelPreset( name, channelInstruments )
channelInstruments = channelInstruments or {}
local preset = {}
local itemCount = 0
local instrumentCount = #self.instruments
for channelIndex, instrumentIndex in pairs( channelInstruments ) do
channelIndex = ValidateInteger( channelIndex, self.FIRST_MIDI_CHANNEL, self.LAST_MIDI_CHANNEL )
instrumentIndex = ValidateInteger( instrumentIndex, 1, instrumentCount )
itemCount = itemCount + 1
preset[channelIndex] = instrumentIndex
end
self.settings.midiChannelPresets[name] = Either( itemCount > 0, preset, nil )
end
function MKeyboard:SetCurrentChannelPreset( name )
name = name or self.settings.midiCurrentPreset
local channelInstruments = {}
local preset = Either( name == nil, {}, self.settings.midiChannelPresets[name] or {} )
for channelIndex, instrumentIndex in pairs( preset ) do
channelInstruments[channelIndex] = instrumentIndex
end
self.settings.midiCurrentPreset = name
self.channelInstruments = channelInstruments
end