mirror of
https://github.com/StyledStrike/musical-keyboard.git
synced 2025-03-04 03:13:36 -05:00
Follow the CFC coding style
This commit is contained in:
parent
cfaf83bda6
commit
d86ccf3922
17
.github/workflows/glualint.yml
vendored
Normal file
17
.github/workflows/glualint.yml
vendored
Normal file
@ -0,0 +1,17 @@
|
||||
name: GLuaLint
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [ master ]
|
||||
|
||||
pull_request:
|
||||
branches: [ master ]
|
||||
|
||||
# Allows running this workflow from the Actions tab
|
||||
workflow_dispatch:
|
||||
|
||||
jobs:
|
||||
Lint:
|
||||
uses: FPtje/GLuaFixer/.github/workflows/glualint.yml@master
|
||||
with:
|
||||
config: "./glualint.json"
|
12
README.md
12
README.md
@ -2,17 +2,27 @@
|
||||
|
||||
A playable keyboard for Garry's Mod
|
||||
|
||||
[](https://github.com/FPtje/GLuaFixer)
|
||||
[](https://steamcommunity.com/sharedfiles/filedetails/?id=2656563609)
|
||||
|
||||
### Features
|
||||
|
||||
- Sheets
|
||||
- Multiple keyboard layouts
|
||||
- Many instruments in one entity
|
||||
- Preserves the key press timings when heard by other players
|
||||
- MIDI support ([Module installation guide](https://steamcommunity.com/workshop/filedetails/discussion/2656563609/3199240042192880687/))
|
||||
- Multi-language *(Help needed! Feel free to open a issue/pull request to add/update language files)*
|
||||
|
||||

|
||||
|
||||
### Notice
|
||||
|
||||
All samples used on this project are part of freely available soundfonts.
|
||||
- **GeneralUser GS:** [Custom License](http://www.schristiancollins.com/generaluser.php)
|
||||
- **Alex's gm soundfont version 1.3:** [Creative Commons Attribution 3.0](https://musical-artifacts.com/artifacts/1390)
|
||||
- **LMMS Presets:** (https://docs.lmms.io/user-manual/8-legal/8.1-license)
|
||||
- **LMMS Presets:** (https://docs.lmms.io/user-manual/8-legal/8.1-license)
|
||||
|
||||
## Contributing
|
||||
|
||||
Please follow the [CFC style guidelines](https://github.com/CFC-Servers/cfc_glua_style_guidelines) before opening pull requests.
|
@ -1,37 +1,45 @@
|
||||
{
|
||||
"lint_maxScopeDepth": 8,
|
||||
"lint_syntaxErrors": true,
|
||||
"lint_syntaxInconsistencies": true,
|
||||
"lint_deprecated": true,
|
||||
"lint_trailingWhitespace": true,
|
||||
"lint_whitespaceStyle": true,
|
||||
"lint_beginnerMistakes": true,
|
||||
"lint_emptyBlocks": true,
|
||||
"lint_shadowing": true,
|
||||
"lint_gotos": true,
|
||||
"lint_goto_identifier": true,
|
||||
"lint_doubleNegations": true,
|
||||
"lint_redundantIfStatements": true,
|
||||
"lint_redundantParentheses": true,
|
||||
"lint_duplicateTableKeys": true,
|
||||
"lint_profanity": true,
|
||||
"lint_unusedVars": true,
|
||||
"lint_unusedParameters": true,
|
||||
"lint_unusedLoopVars": false,
|
||||
"lint_inconsistentVariableStyle": false,
|
||||
"lint_ignoreFiles": [],
|
||||
"lint_maxScopeDepth": 7,
|
||||
"lint_syntaxErrors": true,
|
||||
"lint_syntaxInconsistencies": true,
|
||||
"lint_deprecated": true,
|
||||
"lint_trailingWhitespace": true,
|
||||
"lint_whitespaceStyle": true,
|
||||
"lint_beginnerMistakes": true,
|
||||
"lint_emptyBlocks": true,
|
||||
"lint_shadowing": true,
|
||||
"lint_gotos": true,
|
||||
"lint_goto_identifier": true,
|
||||
"lint_doubleNegations": true,
|
||||
"lint_redundantIfStatements": true,
|
||||
"lint_redundantParentheses": true,
|
||||
"lint_duplicateTableKeys": true,
|
||||
"lint_profanity": true,
|
||||
"lint_unusedVars": true,
|
||||
"lint_unusedParameters": true,
|
||||
"lint_unusedLoopVars": true,
|
||||
"lint_inconsistentVariableStyle": false,
|
||||
"lint_spaceBeforeComma": true,
|
||||
"lint_spaceAfterComma": true,
|
||||
"lint_spaceBetweenParens": true,
|
||||
"lint_spaceBetweenBrackets": true,
|
||||
"lint_spaceBetweenBraces": true,
|
||||
"lint_ignoreFiles": ["**.lua"],
|
||||
|
||||
"prettyprint_spaceAfterParens": true,
|
||||
"prettyprint_spaceAfterBrackets": false,
|
||||
"prettyprint_spaceAfterBraces": false,
|
||||
"prettyprint_spaceEmptyParens": false,
|
||||
"prettyprint_spaceEmptyBraces": false,
|
||||
"prettyprint_spaceAfterLabel": false,
|
||||
"prettyprint_spaceBeforeComma": false,
|
||||
"prettyprint_spaceAfterComma": true,
|
||||
"prettyprint_semicolons": false,
|
||||
"prettyprint_cStyle": false,
|
||||
"prettyprint_rejectInvalidCode": false,
|
||||
"prettyprint_indentation": "\t",
|
||||
"log_format": "auto"
|
||||
"prettyprint_spaceBetweenParens": true,
|
||||
"prettyprint_spaceBetweenBrackets": false,
|
||||
"prettyprint_spaceBetweenBraces": true,
|
||||
"prettyprint_spaceAfterLabel": true,
|
||||
"prettyprint_spaceBeforeComma": false,
|
||||
"prettyprint_spaceAfterComma": true,
|
||||
"prettyprint_semicolons": false,
|
||||
"prettyprint_cStyle": false,
|
||||
"prettyprint_rejectInvalidCode": false,
|
||||
"prettyprint_spaceEmptyParens": false,
|
||||
"prettyprint_spaceEmptyBraces": false,
|
||||
"prettyprint_removeRedundantParens":true,
|
||||
"prettyprint_minimizeParens": true,
|
||||
"prettyprint_assumeOperatorAssociativity": true,
|
||||
"prettyprint_indentation": " ",
|
||||
"log_format": "auto"
|
||||
}
|
@ -1,34 +1,37 @@
|
||||
MKeyboard = {
|
||||
-- max. allowed number of notes per net event
|
||||
NET_MAX_NOTES = 32,
|
||||
-- max. allowed number of notes per net event
|
||||
NET_MAX_NOTES = 32,
|
||||
|
||||
-- players need to be within this distance to receive net events
|
||||
NET_BROADCAST_DISTANCE = 1500,
|
||||
-- players need to be within this distance to receive net events
|
||||
NET_BROADCAST_DISTANCE = 1500,
|
||||
|
||||
-- name/location of the settings file
|
||||
SETTINGS_FILE = 'musical_keyboard.json'
|
||||
-- name/location of the settings file
|
||||
SETTINGS_FILE = 'musical_keyboard.json',
|
||||
|
||||
-- URL for the midi installation guide
|
||||
URL_MIDI_GUIDE = 'https://steamcommunity.com/workshop/filedetails/discussion/2656563609/3199240042192880687/'
|
||||
}
|
||||
|
||||
if SERVER then
|
||||
include('mkeyboard/sv_init.lua')
|
||||
include( 'mkeyboard/sv_init.lua' )
|
||||
|
||||
AddCSLuaFile('mkeyboard/cl_init.lua')
|
||||
AddCSLuaFile('mkeyboard/cl_interface.lua')
|
||||
AddCSLuaFile('mkeyboard/cl_midi.lua')
|
||||
AddCSLuaFile( 'mkeyboard/cl_init.lua' )
|
||||
AddCSLuaFile( 'mkeyboard/cl_interface.lua' )
|
||||
AddCSLuaFile( 'mkeyboard/cl_midi.lua' )
|
||||
|
||||
AddCSLuaFile('mkeyboard/data/instruments.lua')
|
||||
AddCSLuaFile('mkeyboard/data/layouts.lua')
|
||||
AddCSLuaFile('mkeyboard/data/sheets.lua')
|
||||
AddCSLuaFile( 'mkeyboard/data/instruments.lua' )
|
||||
AddCSLuaFile( 'mkeyboard/data/layouts.lua' )
|
||||
AddCSLuaFile( 'mkeyboard/data/sheets.lua' )
|
||||
end
|
||||
|
||||
if CLIENT then
|
||||
include('mkeyboard/cl_init.lua')
|
||||
include('mkeyboard/cl_interface.lua')
|
||||
include('mkeyboard/cl_midi.lua')
|
||||
include( 'mkeyboard/cl_init.lua' )
|
||||
include( 'mkeyboard/cl_interface.lua' )
|
||||
include( 'mkeyboard/cl_midi.lua' )
|
||||
|
||||
include('mkeyboard/data/instruments.lua')
|
||||
include('mkeyboard/data/layouts.lua')
|
||||
include('mkeyboard/data/sheets.lua')
|
||||
include( 'mkeyboard/data/instruments.lua' )
|
||||
include( 'mkeyboard/data/layouts.lua' )
|
||||
include( 'mkeyboard/data/sheets.lua' )
|
||||
|
||||
MKeyboard:LoadSettings()
|
||||
MKeyboard:LoadSettings()
|
||||
end
|
@ -1,81 +1,85 @@
|
||||
include('shared.lua')
|
||||
include( 'shared.lua' )
|
||||
|
||||
local function Fit(val, valMin, valMax, outMin, outMax)
|
||||
return (val - valMin) * (outMax - outMin) / (valMax - valMin) + outMin
|
||||
local function Fit( val, valMin, valMax, outMin, outMax )
|
||||
return ( val - valMin ) * ( outMax - outMin ) / ( valMax - valMin ) + outMin
|
||||
end
|
||||
|
||||
local blackKeys = {
|
||||
[1] = true, [3] = true, [6] = true, [8] = true, [10] = true
|
||||
[1] = true, [3] = true, [6] = true, [8] = true, [10] = true
|
||||
}
|
||||
|
||||
local keyColors = {
|
||||
Color(255, 148, 77),
|
||||
Color(171, 0, 197)
|
||||
Color( 255, 148, 77 ),
|
||||
Color( 171, 0, 197 )
|
||||
}
|
||||
|
||||
local offsetKeys = {
|
||||
[2] = 0.2,
|
||||
[4] = 0.4,
|
||||
[5] = -0.1,
|
||||
[7] = 0.1,
|
||||
[9] = 0.4,
|
||||
[11] = 0.6
|
||||
[2] = 0.2,
|
||||
[4] = 0.4,
|
||||
[5] = -0.1,
|
||||
[7] = 0.1,
|
||||
[9] = 0.4,
|
||||
[11] = 0.6
|
||||
}
|
||||
|
||||
function ENT:Initialize()
|
||||
self.drawNotes = {}
|
||||
self.drawNotes = {}
|
||||
end
|
||||
|
||||
function ENT:EmitNote(note, velocity, level, instrument, automated)
|
||||
local instr = MKeyboard.Instruments[instrument]
|
||||
function ENT:EmitNote( note, velocity, level, instrument, automated )
|
||||
local instr = MKeyboard.instruments[instrument]
|
||||
|
||||
if not instr then return end
|
||||
if note < instr.firstNote or note > instr.lastNote then return end
|
||||
if not instr then return end
|
||||
if note < instr.firstNote or note > instr.lastNote then return end
|
||||
|
||||
-- self:EmitSound(string.format(instr.path, note), level, 100, velocity / 127, CHAN_STATIC, 0)
|
||||
sound.Play(string.format(instr.path, note), self:GetPos(), level, 100, velocity / 127)
|
||||
sound.Play( string.format( instr.path, note ), self:GetPos(), level, 100, velocity / 127 )
|
||||
|
||||
local idx = note % 12
|
||||
local len = 8
|
||||
local height = -0.2
|
||||
local width = 1.6
|
||||
local x = -1.1
|
||||
local idx = note % 12
|
||||
local len = 8
|
||||
local height = -0.2
|
||||
local width = 1.6
|
||||
local x = -1.1
|
||||
|
||||
if blackKeys[idx] then
|
||||
len = 5
|
||||
height = 0.1
|
||||
width = 1
|
||||
x = -0.6
|
||||
end
|
||||
if blackKeys[idx] then
|
||||
len = 5
|
||||
height = 0.1
|
||||
width = 1
|
||||
x = -0.6
|
||||
end
|
||||
|
||||
if offsetKeys[idx] then
|
||||
x = x + offsetKeys[idx]
|
||||
end
|
||||
if offsetKeys[idx] then
|
||||
x = x + offsetKeys[idx]
|
||||
end
|
||||
|
||||
self.drawNotes[note] = {
|
||||
x = Fit(note, 21, 108, -37, 36.7),
|
||||
t = RealTime() + 0.2,
|
||||
min = Vector(x, -1.5, -1),
|
||||
max = Vector(x + width, len, height),
|
||||
colorIdx = automated and 2 or 1
|
||||
}
|
||||
self.drawNotes[note] = {
|
||||
x = Fit( note, 21, 108, -37, 36.7 ),
|
||||
t = RealTime() + 0.2,
|
||||
min = Vector( x, -1.5, -1 ),
|
||||
max = Vector( x + width, len, height ),
|
||||
colorIdx = automated and 2 or 1
|
||||
}
|
||||
end
|
||||
|
||||
function ENT:Draw()
|
||||
self:DrawModel()
|
||||
self:DrawModel()
|
||||
|
||||
local t = RealTime()
|
||||
local ang = self:GetAngles()
|
||||
local t = RealTime()
|
||||
local ang = self:GetAngles()
|
||||
|
||||
render.SetColorMaterial()
|
||||
render.SetColorMaterial()
|
||||
|
||||
for note, p in pairs(self.drawNotes) do
|
||||
if t > p.t then
|
||||
self.drawNotes[note] = nil
|
||||
else
|
||||
local clr = keyColors[p.colorIdx]
|
||||
render.DrawBox(self:LocalToWorld( Vector(-p.x,0,0) ), ang, p.min, p.max,
|
||||
Color(clr.r, clr.g, clr.b, 255 * ((p.t - t) / 0.2)))
|
||||
end
|
||||
end
|
||||
for note, p in pairs( self.drawNotes ) do
|
||||
if t > p.t then
|
||||
self.drawNotes[note] = nil
|
||||
else
|
||||
local clr = keyColors[p.colorIdx]
|
||||
local alpha = 255 * ( ( p.t - t ) / 0.2 )
|
||||
|
||||
render.DrawBox(
|
||||
self:LocalToWorld( Vector( -p.x, 0, 0 ) ),
|
||||
ang, p.min, p.max,
|
||||
Color( clr.r, clr.g, clr.b, alpha )
|
||||
)
|
||||
end
|
||||
end
|
||||
end
|
@ -1,51 +1,51 @@
|
||||
AddCSLuaFile('cl_init.lua')
|
||||
AddCSLuaFile('shared.lua')
|
||||
include('shared.lua')
|
||||
AddCSLuaFile( 'cl_init.lua' )
|
||||
AddCSLuaFile( 'shared.lua' )
|
||||
include( 'shared.lua' )
|
||||
|
||||
function ENT:SpawnFunction(ply, tr)
|
||||
if not tr.Hit then return end
|
||||
function ENT:SpawnFunction( ply, tr )
|
||||
if not tr.Hit then return end
|
||||
|
||||
local ent = ents.Create(self.ClassName)
|
||||
ent:SetPos(tr.HitPos)
|
||||
ent:SetAngles(Angle(0, ply:EyeAngles().y + 90, 0))
|
||||
ent:Spawn()
|
||||
ent:Activate()
|
||||
local ent = ents.Create( self.ClassName )
|
||||
ent:SetPos( tr.HitPos )
|
||||
ent:SetAngles( Angle( 0, ply:EyeAngles().y + 90, 0 ) )
|
||||
ent:Spawn()
|
||||
ent:Activate()
|
||||
|
||||
return ent
|
||||
return ent
|
||||
end
|
||||
|
||||
function ENT:Initialize()
|
||||
self:SetModel('models/styledstrike/musical_keyboard.mdl')
|
||||
self:PhysicsInit(SOLID_VPHYSICS)
|
||||
self:SetMoveType(MOVETYPE_VPHYSICS)
|
||||
self:SetSolid(SOLID_VPHYSICS)
|
||||
self:SetUseType(SIMPLE_USE)
|
||||
self:DrawShadow(true)
|
||||
self:SetModel( 'models/styledstrike/musical_keyboard.mdl' )
|
||||
self:PhysicsInit( SOLID_VPHYSICS )
|
||||
self:SetMoveType( MOVETYPE_VPHYSICS )
|
||||
self:SetSolid( SOLID_VPHYSICS )
|
||||
self:SetUseType( SIMPLE_USE )
|
||||
self:DrawShadow( true )
|
||||
|
||||
local phys = self:GetPhysicsObject()
|
||||
if IsValid(phys) then phys:Wake() end
|
||||
local phys = self:GetPhysicsObject()
|
||||
if IsValid( phys ) then phys:Wake() end
|
||||
end
|
||||
|
||||
function ENT:Use(ply)
|
||||
self:SetPlayer(ply)
|
||||
function ENT:Use( ply )
|
||||
self:SetPlayer( ply )
|
||||
end
|
||||
|
||||
function ENT:SetPlayer(ply)
|
||||
if not IsValid(self.Ply) then
|
||||
net.Start('mkeyboard.set_entity', false)
|
||||
net.WriteEntity(self)
|
||||
net.Send(ply)
|
||||
function ENT:SetPlayer( ply )
|
||||
if not IsValid( self.Ply ) then
|
||||
net.Start( 'mkeyboard.set_entity', false )
|
||||
net.WriteEntity( self )
|
||||
net.Send( ply )
|
||||
|
||||
self.Ply = ply
|
||||
end
|
||||
self.Ply = ply
|
||||
end
|
||||
end
|
||||
|
||||
function ENT:RemovePlayer()
|
||||
if IsValid(self.Ply) then
|
||||
net.Start('mkeyboard.set_entity', false)
|
||||
net.WriteEntity(nil)
|
||||
net.Send(self.Ply)
|
||||
if IsValid( self.Ply ) then
|
||||
net.Start( 'mkeyboard.set_entity', false )
|
||||
net.WriteEntity( nil )
|
||||
net.Send( self.Ply )
|
||||
|
||||
self.Ply = nil
|
||||
end
|
||||
self.Ply = nil
|
||||
end
|
||||
end
|
@ -6,350 +6,366 @@ MKeyboard.queueTimer = nil
|
||||
MKeyboard.queueStart = 0
|
||||
|
||||
MKeyboard.shiftMode = false
|
||||
MKeyboard.noteState = {}
|
||||
MKeyboard.noteStates = {}
|
||||
MKeyboard.blockInput = 0
|
||||
|
||||
-- settings & persistence
|
||||
MKeyboard.Settings = {
|
||||
layout = 1,
|
||||
instrument = 1,
|
||||
sheet = 0,
|
||||
velocity = 127,
|
||||
octave = 0,
|
||||
midiTranspose = 0,
|
||||
MKeyboard.settings = {
|
||||
layout = 1,
|
||||
instrument = 1,
|
||||
sheet = 0,
|
||||
velocity = 127,
|
||||
octave = 0,
|
||||
midiTranspose = 0,
|
||||
|
||||
channelInstruments = {},
|
||||
drawKeyLabels = true
|
||||
channelInstruments = {},
|
||||
drawKeyLabels = true
|
||||
}
|
||||
|
||||
local shortcuts = {
|
||||
[KEY_TAB] = function()
|
||||
RunConsoleCommand('keyboard_leave', MKeyboard.entity:EntIndex())
|
||||
end,
|
||||
[KEY_TAB] = function()
|
||||
RunConsoleCommand( 'keyboard_leave', MKeyboard.entity:EntIndex() )
|
||||
end,
|
||||
|
||||
[KEY_SPACE] = function()
|
||||
MKeyboard.HUD:ToggleExpandedBar()
|
||||
end,
|
||||
[KEY_SPACE] = function()
|
||||
MKeyboard.uiHandler:ToggleExpandedBar()
|
||||
end,
|
||||
|
||||
[KEY_LEFT] = function()
|
||||
MKeyboard.HUD:ChangeInstrument(-1)
|
||||
end,
|
||||
[KEY_LEFT] = function()
|
||||
MKeyboard.uiHandler:ChangeInstrument( -1 )
|
||||
end,
|
||||
|
||||
[KEY_RIGHT] = function()
|
||||
MKeyboard.HUD:ChangeInstrument(1)
|
||||
end,
|
||||
[KEY_RIGHT] = function()
|
||||
MKeyboard.uiHandler:ChangeInstrument( 1 )
|
||||
end,
|
||||
|
||||
[KEY_UP] = function()
|
||||
MKeyboard.HUD:AddOctave(1)
|
||||
end,
|
||||
[KEY_UP] = function()
|
||||
MKeyboard.uiHandler:AddOctave( 1 )
|
||||
end,
|
||||
|
||||
[KEY_DOWN] = function()
|
||||
MKeyboard.HUD:AddOctave(-1)
|
||||
end
|
||||
[KEY_DOWN] = function()
|
||||
MKeyboard.uiHandler:AddOctave( -1 )
|
||||
end
|
||||
}
|
||||
|
||||
local dontBlockBinds = {
|
||||
['+attack'] = true,
|
||||
['+attack2'] = true,
|
||||
['+duck'] = true
|
||||
['+attack'] = true,
|
||||
['+attack2'] = true,
|
||||
['+duck'] = true
|
||||
}
|
||||
|
||||
local function ValidateInteger(n, min, max)
|
||||
return math.Round(math.Clamp(tonumber(n), min, max))
|
||||
local function validateInteger( n, min, max )
|
||||
return math.Round( math.Clamp( tonumber( n ), min, max ) )
|
||||
end
|
||||
|
||||
function MKeyboard:LoadSettings()
|
||||
local rawData = file.Read(self.SETTINGS_FILE, 'DATA')
|
||||
if rawData == nil then return end
|
||||
local rawData = file.Read( self.SETTINGS_FILE, 'DATA' )
|
||||
if rawData == nil then return end
|
||||
|
||||
local data = util.JSONToTable(rawData) or {}
|
||||
local nInstruments = #self.Instruments
|
||||
local data = util.JSONToTable( rawData ) or {}
|
||||
local instrumentCount = #self.instruments
|
||||
|
||||
-- last layout that was used on the keyboard
|
||||
if data.layout then
|
||||
self.Settings.layout = ValidateInteger(data.layout, 1, #self.Layouts)
|
||||
end
|
||||
-- last layout that was used on the keyboard
|
||||
if data.layout then
|
||||
self.settings.layout = validateInteger( data.layout, 1, #self.layouts )
|
||||
end
|
||||
|
||||
-- last instrument that was used on the keyboard
|
||||
if data.instrument then
|
||||
self.Settings.instrument = ValidateInteger(data.instrument, 1, nInstruments)
|
||||
end
|
||||
-- last instrument that was used on the keyboard
|
||||
if data.instrument then
|
||||
self.settings.instrument = validateInteger( data.instrument, 1, instrumentCount )
|
||||
end
|
||||
|
||||
-- last selected sheet
|
||||
if data.sheet then
|
||||
self.Settings.sheet = ValidateInteger(data.sheet, 0, #self.Sheets)
|
||||
end
|
||||
-- last selected sheet
|
||||
if data.sheet then
|
||||
self.settings.sheet = validateInteger( data.sheet, 0, #self.sheets )
|
||||
end
|
||||
|
||||
-- last velocity set by the settings
|
||||
if data.velocity then
|
||||
self.Settings.velocity = ValidateInteger(data.velocity, 1, 127)
|
||||
end
|
||||
-- last velocity set by the settings
|
||||
if data.velocity then
|
||||
self.settings.velocity = validateInteger( data.velocity, 1, 127 )
|
||||
end
|
||||
|
||||
-- last octave that was used on the keyboard
|
||||
if data.octave then
|
||||
self.Settings.octave = ValidateInteger(data.octave, -3, 3)
|
||||
end
|
||||
-- last octave that was used on the keyboard
|
||||
if data.octave then
|
||||
self.settings.octave = validateInteger( data.octave, -3, 3 )
|
||||
end
|
||||
|
||||
-- last transpose that was used with midi
|
||||
if data.midiTranspose then
|
||||
self.Settings.midiTranspose = ValidateInteger(data.midiTranspose, -48, 48)
|
||||
end
|
||||
-- last transpose that was used with midi
|
||||
if data.midiTranspose then
|
||||
self.settings.midiTranspose = validateInteger( data.midiTranspose, -48, 48 )
|
||||
end
|
||||
|
||||
-- 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, nInstruments)
|
||||
-- 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 )
|
||||
|
||||
self.Settings.channelInstruments[channel] = instrument
|
||||
end
|
||||
end
|
||||
self.settings.channelInstruments[channel] = instrument
|
||||
end
|
||||
end
|
||||
|
||||
-- draw labels for keys
|
||||
self.Settings.drawKeyLabels = Either(isbool(data.drawKeyLabels), tobool(data.drawKeyLabels), true)
|
||||
-- draw labels for keys
|
||||
self.settings.drawKeyLabels = Either( isbool( data.drawKeyLabels ), tobool( data.drawKeyLabels ), true )
|
||||
end
|
||||
|
||||
function MKeyboard:SaveSettings()
|
||||
local s = self.Settings
|
||||
local s = self.settings
|
||||
|
||||
file.Write(self.SETTINGS_FILE, util.TableToJSON({
|
||||
layout = s.layout,
|
||||
instrument = s.instrument,
|
||||
sheet = s.sheet,
|
||||
velocity = s.velocity,
|
||||
octave = s.octave,
|
||||
midiTranspose = s.midiTranspose,
|
||||
channelInstruments = s.channelInstruments,
|
||||
drawKeyLabels = s.drawKeyLabels
|
||||
}, true))
|
||||
file.Write(
|
||||
self.SETTINGS_FILE,
|
||||
util.TableToJSON( {
|
||||
layout = s.layout,
|
||||
instrument = s.instrument,
|
||||
sheet = s.sheet,
|
||||
velocity = s.velocity,
|
||||
octave = s.octave,
|
||||
midiTranspose = s.midiTranspose,
|
||||
channelInstruments = s.channelInstruments,
|
||||
drawKeyLabels = s.drawKeyLabels
|
||||
}, true )
|
||||
)
|
||||
end
|
||||
|
||||
function MKeyboard:Init(ent)
|
||||
self.entity = ent
|
||||
self.blockInput = RealTime() + 0.3
|
||||
function MKeyboard:Init( ent )
|
||||
self.entity = ent
|
||||
self.blockInput = RealTime() + 0.3
|
||||
|
||||
self.HUD:Init()
|
||||
self.uiHandler:Init()
|
||||
|
||||
hook.Add('Think', 'mkeyboard_Think', function()
|
||||
self:Think()
|
||||
end)
|
||||
hook.Add( 'Think', 'mkeyboard_ProcessLocalKeyboard', function()
|
||||
self:Think()
|
||||
end )
|
||||
|
||||
hook.Add('PlayerButtonDown', 'mkeyboard_PlayerButtonDown', function(ply, button)
|
||||
if ply == LocalPlayer() and IsFirstTimePredicted() then
|
||||
self:OnButton(button, true)
|
||||
end
|
||||
end)
|
||||
hook.Add( 'PlayerButtonDown', 'mkeyboard_LocalButtonPress', function( ply, button )
|
||||
if ply == LocalPlayer() and IsFirstTimePredicted() then
|
||||
self:OnButton( button, true )
|
||||
end
|
||||
end )
|
||||
|
||||
hook.Add('PlayerButtonUp', 'mkeyboard_PlayerButtonUp', function(ply, button)
|
||||
if ply == LocalPlayer() and IsFirstTimePredicted() then
|
||||
self:OnButton(button, false)
|
||||
end
|
||||
end)
|
||||
hook.Add( 'PlayerButtonUp', 'mkeyboard_LocalButtonRelease', function( ply, button )
|
||||
if ply == LocalPlayer() and IsFirstTimePredicted() then
|
||||
self:OnButton( button, false )
|
||||
end
|
||||
end )
|
||||
|
||||
hook.Add('PlayerBindPress', 'mkeyboard_PlayerBindPress', function(_, bind)
|
||||
if not dontBlockBinds[bind] then return true end
|
||||
end)
|
||||
hook.Add( 'PlayerBindPress', 'mkeyboard_BlockBinds', function( _, bind )
|
||||
if not dontBlockBinds[bind] then return true end
|
||||
end )
|
||||
|
||||
-- Custom Chat compatibility
|
||||
hook.Add('BlockChatInput', 'mkeyboard_BlockChatInput', function()
|
||||
return true
|
||||
end)
|
||||
-- Custom Chat compatibility
|
||||
hook.Add( 'BlockChatInput', 'mkeyboard_PreventOpeningChat', function()
|
||||
return true
|
||||
end )
|
||||
end
|
||||
|
||||
function MKeyboard:Shutdown()
|
||||
self.entity = nil
|
||||
self.entity = nil
|
||||
|
||||
self.transmitQueue = {}
|
||||
self.queueTimer = nil
|
||||
self.transmitQueue = {}
|
||||
self.queueTimer = nil
|
||||
|
||||
self.shiftMode = false
|
||||
self.noteState = {}
|
||||
self.shiftMode = false
|
||||
self.noteStates = {}
|
||||
|
||||
self.MIDI:Close()
|
||||
self.HUD:Shutdown()
|
||||
self.midiHandler:Close()
|
||||
self.uiHandler:Shutdown()
|
||||
|
||||
hook.Remove('Think', 'mkeyboard_Think')
|
||||
hook.Remove('PlayerButtonDown', 'mkeyboard_PlayerButtonDown')
|
||||
hook.Remove('PlayerButtonUp', 'mkeyboard_PlayerButtonUp')
|
||||
hook.Remove('PlayerBindPress', 'mkeyboard_PlayerBindPress')
|
||||
hook.Remove('BlockChatInput', 'mkeyboard_BlockChatInput')
|
||||
hook.Remove( 'Think', 'mkeyboard_ProcessLocalKeyboard' )
|
||||
hook.Remove( 'PlayerButtonDown', 'mkeyboard_LocalButtonPress' )
|
||||
hook.Remove( 'PlayerButtonUp', 'mkeyboard_LocalButtonRelease' )
|
||||
hook.Remove( 'PlayerBindPress', 'mkeyboard_BlockBinds' )
|
||||
hook.Remove( 'BlockChatInput', 'mkeyboard_PreventOpeningChat' )
|
||||
end
|
||||
|
||||
function MKeyboard:NoteOn(note, velocity, isMidi, midiChannel)
|
||||
local instrument = self.Settings.instrument
|
||||
function MKeyboard:NoteOn( note, velocity, isMidi, midiChannel )
|
||||
local instrument = self.settings.instrument
|
||||
|
||||
if midiChannel then
|
||||
self.HUD.channelState[midiChannel] = 1
|
||||
instrument = self.Settings.channelInstruments[midiChannel] or instrument
|
||||
if midiChannel then
|
||||
self.uiHandler.channelState[midiChannel] = 1
|
||||
instrument = self.settings.channelInstruments[midiChannel] or instrument
|
||||
|
||||
if instrument == 0 then return end
|
||||
end
|
||||
if instrument == 0 then return end
|
||||
end
|
||||
|
||||
local instr = self.Instruments[instrument]
|
||||
if note < instr.firstNote or note > instr.lastNote then return end
|
||||
local instr = self.instruments[instrument]
|
||||
if note < instr.firstNote or note > instr.lastNote then return end
|
||||
|
||||
self.entity:EmitNote(note, velocity, 80, instrument, isMidi)
|
||||
self.entity:EmitNote( note, velocity, 80, instrument, isMidi )
|
||||
|
||||
self.noteState[note] = isMidi and 4 or 3 -- see themeColors on cl_interface.lua
|
||||
self.lastNoteWasAutomated = isMidi
|
||||
self.noteStates[note] = isMidi and 'midi' or 'on'
|
||||
self.lastNoteWasAutomated = isMidi
|
||||
|
||||
-- remember when we started putting notes
|
||||
-- on the queue, and when we should send them
|
||||
local t = SysTime()
|
||||
-- remember when we started putting notes
|
||||
-- on the queue, and when we should send them
|
||||
local t = SysTime()
|
||||
|
||||
if not self.queueTimer then
|
||||
self.queueTimer = t + 0.4
|
||||
self.queueStart = t
|
||||
end
|
||||
if not self.queueTimer then
|
||||
self.queueTimer = t + 0.4
|
||||
self.queueStart = t
|
||||
end
|
||||
|
||||
-- add notes to the queue unless the limit is was reached
|
||||
local noteCount = #self.transmitQueue
|
||||
if noteCount < self.NET_MAX_NOTES then
|
||||
self.transmitQueue[noteCount + 1] = { note, velocity, instrument, t - self.queueStart }
|
||||
end
|
||||
-- add notes to the queue unless the limit is was reached
|
||||
local noteCount = #self.transmitQueue
|
||||
if noteCount < self.NET_MAX_NOTES then
|
||||
self.transmitQueue[noteCount + 1] = { note, velocity, instrument, t - self.queueStart }
|
||||
end
|
||||
end
|
||||
|
||||
function MKeyboard:NoteOff(note)
|
||||
self.noteState[note] = nil
|
||||
function MKeyboard:NoteOff( note )
|
||||
self.noteStates[note] = nil
|
||||
end
|
||||
|
||||
function MKeyboard:NoteOffAll()
|
||||
for k, _ in pairs(self.noteState) do
|
||||
self.noteState[k] = nil
|
||||
end
|
||||
for k, _ in pairs( self.noteStates ) do
|
||||
self.noteStates[k] = nil
|
||||
end
|
||||
end
|
||||
|
||||
function MKeyboard:ReproduceQueue()
|
||||
local t = SysTime()
|
||||
local t = SysTime()
|
||||
|
||||
-- play the networked notes, keeping the original timings
|
||||
for time, data in pairs(self.reproduceQueue) do
|
||||
if t > time then
|
||||
if IsValid(data[1]) then
|
||||
data[1]:EmitNote(data[2], data[3], 80, data[4], data[5])
|
||||
end
|
||||
-- play the networked notes, keeping the original timings
|
||||
for time, data in pairs( self.reproduceQueue ) do
|
||||
if t > time then
|
||||
if IsValid( data[1] ) then
|
||||
data[1]:EmitNote( data[2], data[3], 80, data[4], data[5] )
|
||||
end
|
||||
|
||||
self.reproduceQueue[time] = nil
|
||||
end
|
||||
end
|
||||
self.reproduceQueue[time] = nil
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function MKeyboard:TransmitQueue()
|
||||
net.Start('mkeyboard.notes', false)
|
||||
net.WriteEntity(self.entity)
|
||||
net.WriteBool(self.lastNoteWasAutomated)
|
||||
net.WriteUInt(#self.transmitQueue, 5)
|
||||
net.Start( 'mkeyboard.notes', false )
|
||||
net.WriteEntity( self.entity )
|
||||
net.WriteBool( self.lastNoteWasAutomated )
|
||||
net.WriteUInt( #self.transmitQueue, 5 )
|
||||
|
||||
for _, params in ipairs(self.transmitQueue) do
|
||||
net.WriteUInt(params[1], 7) -- note
|
||||
net.WriteUInt(params[2], 7) -- velocity
|
||||
net.WriteUInt(params[3], 6) -- instrument
|
||||
net.WriteFloat(params[4]) -- time offset
|
||||
end
|
||||
for _, params in ipairs( self.transmitQueue ) do
|
||||
net.WriteUInt( params[1], 7 ) -- note
|
||||
net.WriteUInt( params[2], 7 ) -- velocity
|
||||
net.WriteUInt( params[3], 6 ) -- instrument
|
||||
net.WriteFloat( params[4] ) -- time offset
|
||||
end
|
||||
|
||||
net.SendToServer()
|
||||
net.SendToServer()
|
||||
|
||||
table.Empty(self.transmitQueue)
|
||||
self.queueTimer = nil
|
||||
table.Empty( self.transmitQueue )
|
||||
self.queueTimer = nil
|
||||
end
|
||||
|
||||
function MKeyboard:Think()
|
||||
if not IsValid(self.entity) then
|
||||
self:Shutdown()
|
||||
return
|
||||
end
|
||||
if not IsValid( self.entity ) then
|
||||
self:Shutdown()
|
||||
|
||||
self.MIDI:Think()
|
||||
return
|
||||
end
|
||||
|
||||
local t = SysTime()
|
||||
self.midiHandler:Think()
|
||||
|
||||
-- if the queued notes are ready to be sent...
|
||||
if self.queueTimer and t > self.queueTimer then
|
||||
self:TransmitQueue()
|
||||
end
|
||||
local t = SysTime()
|
||||
|
||||
-- if the queued notes are ready to be sent...
|
||||
if self.queueTimer and t > self.queueTimer then
|
||||
self:TransmitQueue()
|
||||
end
|
||||
end
|
||||
|
||||
function MKeyboard:OnButton(button, isPressed)
|
||||
if button == KEY_LSHIFT then
|
||||
self.shiftMode = isPressed
|
||||
end
|
||||
function MKeyboard:OnButton( button, isPressed )
|
||||
if button == KEY_LSHIFT then
|
||||
self.shiftMode = isPressed
|
||||
end
|
||||
|
||||
-- process shortcuts
|
||||
if shortcuts[button] and not isPressed then
|
||||
shortcuts[button]()
|
||||
return
|
||||
end
|
||||
-- process shortcuts
|
||||
if shortcuts[button] and not isPressed then
|
||||
shortcuts[button]()
|
||||
return
|
||||
end
|
||||
|
||||
if self.blockInput > RealTime() then return end
|
||||
if self.blockInput > RealTime() then return end
|
||||
|
||||
local layoutKeys = self.Layouts[self.Settings.layout].keys
|
||||
local layoutKeys = self.layouts[self.settings.layout].keys
|
||||
|
||||
-- process layout keys
|
||||
for idx, params in ipairs(layoutKeys) do
|
||||
-- params: key [1], note [2], type [3], label [4], require SHIFT [5], alternative key [6]
|
||||
-- process layout keys
|
||||
for _, params in ipairs( layoutKeys ) do
|
||||
--[[ params:
|
||||
key [1],
|
||||
note [2],
|
||||
type [3],
|
||||
label [4],
|
||||
require SHIFT [5],
|
||||
alternative key [6]
|
||||
]]
|
||||
|
||||
if params[1] == button or (params[6] and params[6] == button) then
|
||||
local note = params[2] + self.Settings.octave * 12
|
||||
-- if either the "main" or "alternative" buttons are pressed for this key...
|
||||
if params[1] == button or ( params[6] and params[6] == button ) then
|
||||
local note = params[2] + self.settings.octave * 12
|
||||
|
||||
if isPressed then
|
||||
if params[5] and self.shiftMode then
|
||||
self:NoteOn(note, self.Settings.velocity, false)
|
||||
break
|
||||
end
|
||||
if isPressed then
|
||||
-- if this key requires shift and shift is pressed...
|
||||
if params[5] and self.shiftMode then
|
||||
self:NoteOn( note, self.settings.velocity, false )
|
||||
break
|
||||
end
|
||||
|
||||
if not params[5] and not self.shiftMode then
|
||||
self:NoteOn(note, self.Settings.velocity, false)
|
||||
break
|
||||
end
|
||||
else
|
||||
self:NoteOff(note)
|
||||
end
|
||||
end
|
||||
end
|
||||
-- if this key does NOT require shift and shift is NOT pressed...
|
||||
if not params[5] and not self.shiftMode then
|
||||
self:NoteOn( note, self.settings.velocity, false )
|
||||
break
|
||||
end
|
||||
else
|
||||
self:NoteOff( note )
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
hook.Add('Think', 'mkeyboard_OffscreenThink', function()
|
||||
MKeyboard:ReproduceQueue()
|
||||
end)
|
||||
hook.Add( 'Think', 'mkeyboard_ProcessReproductionQueue', function()
|
||||
MKeyboard:ReproduceQueue()
|
||||
end )
|
||||
|
||||
net.Receive('mkeyboard.set_entity', function()
|
||||
local ent = net.ReadEntity()
|
||||
net.Receive( 'mkeyboard.set_entity', function()
|
||||
local ent = net.ReadEntity()
|
||||
|
||||
MKeyboard:Shutdown()
|
||||
MKeyboard:Shutdown()
|
||||
|
||||
if IsValid(ent) then
|
||||
MKeyboard:Init(ent)
|
||||
end
|
||||
end)
|
||||
if IsValid( ent ) then
|
||||
MKeyboard:Init( ent )
|
||||
end
|
||||
end )
|
||||
|
||||
net.Receive('mkeyboard.notes', function()
|
||||
local ent = net.ReadEntity()
|
||||
if not IsValid(ent) or not ent.EmitNote then return end
|
||||
net.Receive( 'mkeyboard.notes', function()
|
||||
local ent = net.ReadEntity()
|
||||
if not IsValid( ent ) or not ent.EmitNote then return end
|
||||
|
||||
local automated = net.ReadBool()
|
||||
local noteCount = net.ReadUInt(5)
|
||||
local note, vel, instr, timeOffset
|
||||
local automated = net.ReadBool()
|
||||
local noteCount = net.ReadUInt( 5 )
|
||||
local note, vel, instr, timeOffset
|
||||
|
||||
local t = SysTime()
|
||||
local t = SysTime()
|
||||
local i = 1
|
||||
|
||||
for i = 1, noteCount do
|
||||
note = net.ReadUInt(7)
|
||||
vel = net.ReadUInt(7)
|
||||
instr = net.ReadUInt(6)
|
||||
timeOffset = net.ReadFloat()
|
||||
while i < noteCount do
|
||||
note = net.ReadUInt( 7 )
|
||||
vel = net.ReadUInt( 7 )
|
||||
instr = net.ReadUInt( 6 )
|
||||
timeOffset = net.ReadFloat()
|
||||
|
||||
MKeyboard.reproduceQueue[t + timeOffset] = { ent, note, vel, instr, automated }
|
||||
end
|
||||
end)
|
||||
MKeyboard.reproduceQueue[t + timeOffset] = { ent, note, vel, instr, automated }
|
||||
i = i + 1
|
||||
end
|
||||
end )
|
||||
|
||||
-- net event that only runs on single-player
|
||||
-- key press/release net event that only runs on single-player
|
||||
if game.SinglePlayer() then
|
||||
net.Receive('mkeyboard.key', function()
|
||||
local button = net.ReadUInt(8)
|
||||
local pressed = net.ReadBool()
|
||||
net.Receive( 'mkeyboard.key', function()
|
||||
local button = net.ReadUInt( 8 )
|
||||
local pressed = net.ReadBool()
|
||||
|
||||
if IsValid(MKeyboard.entity) then
|
||||
MKeyboard:OnButton(button, pressed)
|
||||
end
|
||||
end)
|
||||
if IsValid( MKeyboard.entity ) then
|
||||
MKeyboard:OnButton( button, pressed )
|
||||
end
|
||||
end )
|
||||
end
|
File diff suppressed because it is too large
Load Diff
@ -1,89 +1,91 @@
|
||||
-- based on Starfall's SF.Require, for clientside use
|
||||
local function SafeRequireModule(moduleName)
|
||||
local osSuffix
|
||||
local function SafeRequireModule( moduleName )
|
||||
local osSuffix
|
||||
|
||||
if system.IsWindows() then
|
||||
osSuffix = (jit.arch ~= 'x64' and 'win32' or 'win64')
|
||||
elseif system.IsLinux() then
|
||||
osSuffix = (jit.arch ~= 'x64' and 'linux' or 'linux64')
|
||||
elseif system.IsOSX() then
|
||||
osSuffix = (jit.arch ~= 'x64' and 'osx' or 'osx64')
|
||||
else
|
||||
return
|
||||
end
|
||||
if system.IsWindows() then
|
||||
osSuffix = jit.arch ~= 'x64' and 'win32' or 'win64'
|
||||
elseif system.IsLinux() then
|
||||
osSuffix = jit.arch ~= 'x64' and 'linux' or 'linux64'
|
||||
elseif system.IsOSX() then
|
||||
osSuffix = jit.arch ~= 'x64' and 'osx' or 'osx64'
|
||||
else
|
||||
return
|
||||
end
|
||||
|
||||
if file.Exists('lua/bin/gmcl_' .. moduleName .. '_' .. osSuffix .. '.dll', 'GAME') then
|
||||
local ok, err = pcall(require, moduleName)
|
||||
if ok then
|
||||
return true
|
||||
else
|
||||
ErrorNoHalt(err)
|
||||
return false
|
||||
end
|
||||
end
|
||||
if file.Exists( 'lua/bin/gmcl_' .. moduleName .. '_' .. osSuffix .. '.dll', 'GAME' ) then
|
||||
local ok, err = pcall( require, moduleName )
|
||||
if ok then
|
||||
return true
|
||||
else
|
||||
ErrorNoHalt( err )
|
||||
|
||||
return false
|
||||
return false
|
||||
end
|
||||
end
|
||||
|
||||
return false
|
||||
end
|
||||
|
||||
-- safely require the midi module
|
||||
SafeRequireModule('midi')
|
||||
SafeRequireModule( 'midi' )
|
||||
|
||||
local MIDI = {
|
||||
selectedPort = nil,
|
||||
portTimer = 0
|
||||
local midiHandler = {
|
||||
selectedPort = nil,
|
||||
portTimer = 0
|
||||
}
|
||||
|
||||
MKeyboard.MIDI = MIDI
|
||||
MKeyboard.midiHandler = midiHandler
|
||||
|
||||
function MIDI:Open(port)
|
||||
self:Close()
|
||||
function midiHandler:Open( port )
|
||||
self:Close()
|
||||
|
||||
local portName = midi.GetPorts()[port]
|
||||
if not portName then
|
||||
print('Could not find MIDI port: ' .. port)
|
||||
return
|
||||
end
|
||||
local portName = midi.GetPorts()[port]
|
||||
if not portName then
|
||||
print( 'Could not find MIDI port: ' .. port )
|
||||
|
||||
print('Opening MIDI port: ' .. portName)
|
||||
return
|
||||
end
|
||||
|
||||
local success, err = pcall(midi.Open, port)
|
||||
if success then
|
||||
MKeyboard.HUD:SetMidiPortName(portName)
|
||||
else
|
||||
print('Failed to open MIDI port: ' .. err)
|
||||
end
|
||||
print( 'Opening MIDI port: ' .. portName )
|
||||
|
||||
local success, err = pcall( midi.Open, port )
|
||||
if success then
|
||||
MKeyboard.uiHandler:SetMidiPortName( portName )
|
||||
else
|
||||
print( 'Failed to open MIDI port: ' .. err )
|
||||
end
|
||||
end
|
||||
|
||||
function MIDI:Close()
|
||||
MKeyboard.HUD:SetMidiPortName(nil)
|
||||
function midiHandler:Close()
|
||||
MKeyboard.uiHandler:SetMidiPortName( nil )
|
||||
|
||||
if midi and midi.IsOpened() then
|
||||
print('Closing MIDI port.')
|
||||
midi.Close()
|
||||
end
|
||||
if midi and midi.IsOpened() then
|
||||
print( 'Closing MIDI port.' )
|
||||
midi.Close()
|
||||
end
|
||||
end
|
||||
|
||||
function MIDI:Think()
|
||||
-- Try to open the selected midi port
|
||||
if self.selectedPort and not midi.IsOpened() and RealTime() > self.portTimer then
|
||||
self.portTimer = RealTime() + 5
|
||||
self:Open(self.selectedPort)
|
||||
end
|
||||
function midiHandler:Think()
|
||||
-- Try to open the selected midi port
|
||||
if self.selectedPort and not midi.IsOpened() and RealTime() > self.portTimer then
|
||||
self.portTimer = RealTime() + 5
|
||||
self:Open( self.selectedPort )
|
||||
end
|
||||
end
|
||||
|
||||
-- listen to events from the MIDI module
|
||||
hook.Add('MIDI', 'mkeyboard_MIDI', function(_, code, p1, p2)
|
||||
if not IsValid(MKeyboard.entity) then return end
|
||||
if not code then return end
|
||||
hook.Add( 'MIDI', 'mkeyboard_CaptureMIDIEvents', function( _, code, p1, p2 )
|
||||
if not IsValid( MKeyboard.entity ) then return end
|
||||
if not code then return end
|
||||
|
||||
local midiCmd = midi.GetCommandName(code)
|
||||
local transpose = MKeyboard.Settings.midiTranspose
|
||||
local midiCmd = midi.GetCommandName( code )
|
||||
local transpose = MKeyboard.settings.midiTranspose
|
||||
|
||||
if midiCmd == 'NOTE_ON' and p2 > 0 then
|
||||
local midiChannel = midi.GetCommandChannel(code)
|
||||
MKeyboard:NoteOn(p1 + transpose, p2, true, midiChannel)
|
||||
if midiCmd == 'NOTE_ON' and p2 > 0 then
|
||||
local midiChannel = midi.GetCommandChannel( code )
|
||||
MKeyboard:NoteOn( p1 + transpose, p2, true, midiChannel )
|
||||
|
||||
elseif midiCmd == 'NOTE_OFF' then
|
||||
MKeyboard:NoteOff(p1 + transpose)
|
||||
end
|
||||
end)
|
||||
elseif midiCmd == 'NOTE_OFF' then
|
||||
MKeyboard:NoteOff( p1 + transpose )
|
||||
end
|
||||
end )
|
@ -1,47 +1,47 @@
|
||||
MKeyboard.Instruments = {}
|
||||
MKeyboard.instruments = {}
|
||||
|
||||
function MKeyboard:RegisterInstrument(name, path, firstNote, lastNote)
|
||||
self.Instruments[#self.Instruments + 1] = {
|
||||
name = name,
|
||||
path = path,
|
||||
firstNote = firstNote,
|
||||
lastNote = lastNote
|
||||
}
|
||||
function MKeyboard:RegisterInstrument( name, path, firstNote, lastNote )
|
||||
self.instruments[#self.instruments + 1] = {
|
||||
name = name,
|
||||
path = path,
|
||||
firstNote = firstNote,
|
||||
lastNote = lastNote
|
||||
}
|
||||
end
|
||||
|
||||
-- ##### Default instruments ##### --
|
||||
-- default instruments
|
||||
|
||||
MKeyboard:RegisterInstrument('Grand Piano', 'styledstrike/instruments/grand_piano/%i.mp3', 24, 96)
|
||||
MKeyboard:RegisterInstrument('Grand Piano (Soft)', 'styledstrike/instruments/grand_piano_2/%i.mp3', 24, 96)
|
||||
MKeyboard:RegisterInstrument('Electric Piano', 'styledstrike/instruments/electric_piano/%i.mp3', 24, 96)
|
||||
MKeyboard:RegisterInstrument('Analog Piano', 'styledstrike/instruments/analog_piano/%i.mp3', 24, 108)
|
||||
MKeyboard:RegisterInstrument('Binary Piano', 'styledstrike/instruments/binary_piano/%i.mp3', 24, 96)
|
||||
MKeyboard:RegisterInstrument( 'Grand Piano', 'styledstrike/instruments/grand_piano/%i.mp3', 24, 96 )
|
||||
MKeyboard:RegisterInstrument( 'Grand Piano (Soft)', 'styledstrike/instruments/grand_piano_2/%i.mp3', 24, 96 )
|
||||
MKeyboard:RegisterInstrument( 'Electric Piano', 'styledstrike/instruments/electric_piano/%i.mp3', 24, 96 )
|
||||
MKeyboard:RegisterInstrument( 'Analog Piano', 'styledstrike/instruments/analog_piano/%i.mp3', 24, 108 )
|
||||
MKeyboard:RegisterInstrument( 'Binary Piano', 'styledstrike/instruments/binary_piano/%i.mp3', 24, 96 )
|
||||
|
||||
MKeyboard:RegisterInstrument('Music Box', 'styledstrike/instruments/music_box/%i.mp3', 36, 96)
|
||||
MKeyboard:RegisterInstrument('Harp', 'styledstrike/instruments/harp/%i.mp3', 24, 96)
|
||||
MKeyboard:RegisterInstrument('Harpsichord', 'styledstrike/instruments/harpsichord/%i.mp3', 24, 96)
|
||||
MKeyboard:RegisterInstrument('Nylon Guitar', 'styledstrike/instruments/nylon_guitar/%i.mp3', 24, 96)
|
||||
MKeyboard:RegisterInstrument('Jazz Guitar', 'styledstrike/instruments/jazz_guitar/%i.mp3', 24, 84)
|
||||
MKeyboard:RegisterInstrument('Picked Bass', 'styledstrike/instruments/picked_bass/%i.mp3', 24, 72)
|
||||
MKeyboard:RegisterInstrument('Slap Bass', 'styledstrike/instruments/slap_bass/%i.mp3', 24, 72)
|
||||
MKeyboard:RegisterInstrument('Acoustic Bass', 'styledstrike/instruments/acoustic_bass/%i.mp3', 24, 72)
|
||||
MKeyboard:RegisterInstrument( 'Music Box', 'styledstrike/instruments/music_box/%i.mp3', 36, 96 )
|
||||
MKeyboard:RegisterInstrument( 'Harp', 'styledstrike/instruments/harp/%i.mp3', 24, 96 )
|
||||
MKeyboard:RegisterInstrument( 'Harpsichord', 'styledstrike/instruments/harpsichord/%i.mp3', 24, 96 )
|
||||
MKeyboard:RegisterInstrument( 'Nylon Guitar', 'styledstrike/instruments/nylon_guitar/%i.mp3', 24, 96 )
|
||||
MKeyboard:RegisterInstrument( 'Jazz Guitar', 'styledstrike/instruments/jazz_guitar/%i.mp3', 24, 84 )
|
||||
MKeyboard:RegisterInstrument( 'Picked Bass', 'styledstrike/instruments/picked_bass/%i.mp3', 24, 72 )
|
||||
MKeyboard:RegisterInstrument( 'Slap Bass', 'styledstrike/instruments/slap_bass/%i.mp3', 24, 72 )
|
||||
MKeyboard:RegisterInstrument( 'Acoustic Bass', 'styledstrike/instruments/acoustic_bass/%i.mp3', 24, 72 )
|
||||
|
||||
MKeyboard:RegisterInstrument('Marimba', 'styledstrike/instruments/marimba/%i.mp3', 36, 96)
|
||||
MKeyboard:RegisterInstrument('Vibraphone', 'styledstrike/instruments/vibraphone/%i.mp3', 36, 96)
|
||||
MKeyboard:RegisterInstrument('Piccolo', 'styledstrike/instruments/piccolo/%i.mp3', 48, 96)
|
||||
MKeyboard:RegisterInstrument('Pizzicato Strings', 'styledstrike/instruments/pizzicato_strings/%i.mp3', 24, 96)
|
||||
MKeyboard:RegisterInstrument('Choir Oohs', 'styledstrike/instruments/choir_oohs/%i.mp3', 36, 96)
|
||||
MKeyboard:RegisterInstrument( 'Marimba', 'styledstrike/instruments/marimba/%i.mp3', 36, 96 )
|
||||
MKeyboard:RegisterInstrument( 'Vibraphone', 'styledstrike/instruments/vibraphone/%i.mp3', 36, 96 )
|
||||
MKeyboard:RegisterInstrument( 'Piccolo', 'styledstrike/instruments/piccolo/%i.mp3', 48, 96 )
|
||||
MKeyboard:RegisterInstrument( 'Pizzicato Strings', 'styledstrike/instruments/pizzicato_strings/%i.mp3', 24, 96 )
|
||||
MKeyboard:RegisterInstrument( 'Choir Oohs', 'styledstrike/instruments/choir_oohs/%i.mp3', 36, 96 )
|
||||
|
||||
MKeyboard:RegisterInstrument('New Age', 'styledstrike/instruments/new_age/%i.mp3', 24, 96)
|
||||
MKeyboard:RegisterInstrument('Polysynth', 'styledstrike/instruments/polysynth/%i.mp3', 24, 96)
|
||||
MKeyboard:RegisterInstrument('Soft Synth', 'styledstrike/instruments/soft_synth/%i.mp3', 24, 96)
|
||||
MKeyboard:RegisterInstrument('Space Voice', 'styledstrike/instruments/space_voice/%i.mp3', 36, 96)
|
||||
MKeyboard:RegisterInstrument('Saw Lead', 'styledstrike/instruments/saw_lead/%i.mp3', 24, 96)
|
||||
MKeyboard:RegisterInstrument('Square Lead', 'styledstrike/instruments/square_lead/%i.mp3', 24, 96)
|
||||
MKeyboard:RegisterInstrument( 'New Age', 'styledstrike/instruments/new_age/%i.mp3', 24, 96 )
|
||||
MKeyboard:RegisterInstrument( 'Polysynth', 'styledstrike/instruments/polysynth/%i.mp3', 24, 96 )
|
||||
MKeyboard:RegisterInstrument( 'Soft Synth', 'styledstrike/instruments/soft_synth/%i.mp3', 24, 96 )
|
||||
MKeyboard:RegisterInstrument( 'Space Voice', 'styledstrike/instruments/space_voice/%i.mp3', 36, 96 )
|
||||
MKeyboard:RegisterInstrument( 'Saw Lead', 'styledstrike/instruments/saw_lead/%i.mp3', 24, 96 )
|
||||
MKeyboard:RegisterInstrument( 'Square Lead', 'styledstrike/instruments/square_lead/%i.mp3', 24, 96 )
|
||||
|
||||
MKeyboard:RegisterInstrument('Drums (Standard)', 'styledstrike/instruments/drums_standard/%i.mp3', 26, 87)
|
||||
MKeyboard:RegisterInstrument('Drums (Analog)', 'styledstrike/instruments/drums_analog/%i.mp3', 26, 75)
|
||||
MKeyboard:RegisterInstrument('Drums (Jazz)', 'styledstrike/instruments/drums_jazz/%i.mp3', 26, 75)
|
||||
MKeyboard:RegisterInstrument('Drums (Brush)', 'styledstrike/instruments/drums_brush/%i.mp3', 26, 75)
|
||||
MKeyboard:RegisterInstrument( 'Drums (Standard)', 'styledstrike/instruments/drums_standard/%i.mp3', 26, 87 )
|
||||
MKeyboard:RegisterInstrument( 'Drums (Analog)', 'styledstrike/instruments/drums_analog/%i.mp3', 26, 75 )
|
||||
MKeyboard:RegisterInstrument( 'Drums (Jazz)', 'styledstrike/instruments/drums_jazz/%i.mp3', 26, 75 )
|
||||
MKeyboard:RegisterInstrument( 'Drums (Brush)', 'styledstrike/instruments/drums_brush/%i.mp3', 26, 75 )
|
||||
|
||||
MKeyboard:RegisterInstrument('Honky Tonk', 'styledstrike/instruments/honky_tonk/%i.mp3', 24, 96)
|
||||
MKeyboard:RegisterInstrument( 'Honky Tonk', 'styledstrike/instruments/honky_tonk/%i.mp3', 24, 96 )
|
@ -1,144 +1,144 @@
|
||||
MKeyboard.Layouts = {}
|
||||
MKeyboard.layouts = {}
|
||||
|
||||
function MKeyboard:RegisterLayout(name, keys, octaveLimits)
|
||||
self.Layouts[#self.Layouts + 1] = {
|
||||
name = name,
|
||||
keys = keys,
|
||||
octaveLimits = octaveLimits
|
||||
}
|
||||
function MKeyboard:RegisterLayout( name, keys, octaveLimits )
|
||||
self.layouts[#self.layouts + 1] = {
|
||||
name = name,
|
||||
keys = keys,
|
||||
octaveLimits = octaveLimits
|
||||
}
|
||||
end
|
||||
|
||||
-- ##### Default keyboard layouts ##### --
|
||||
-- default keyboard layouts
|
||||
|
||||
MKeyboard:RegisterLayout('Compact', {
|
||||
-- key, note, type, label
|
||||
{KEY_A, 60, 'w', 'a'},
|
||||
{KEY_W, 61, 'b', 'w'},
|
||||
{KEY_S, 62, 'w', 's'},
|
||||
{KEY_E, 63, 'b', 'e'},
|
||||
{KEY_D, 64, 'w', 'd'},
|
||||
{KEY_F, 65, 'w', 'f'},
|
||||
{KEY_T, 66, 'b', 't'},
|
||||
{KEY_G, 67, 'w', 'g'},
|
||||
{KEY_Y, 68, 'b', 'y'},
|
||||
{KEY_H, 69, 'w', 'h'},
|
||||
{KEY_U, 70, 'b', 'u'},
|
||||
{KEY_J, 71, 'w', 'j'},
|
||||
{KEY_K, 72, 'w', 'k'},
|
||||
{KEY_O, 73, 'b', 'o'},
|
||||
{KEY_L, 74, 'w', 'l'},
|
||||
{KEY_P, 75, 'b', 'p'},
|
||||
{KEY_SEMICOLON, 76, 'w', ';'},
|
||||
{KEY_APOSTROPHE, 77, 'w', '\''}
|
||||
MKeyboard:RegisterLayout( 'Compact', {
|
||||
-- key, note, type, label
|
||||
{ KEY_A, 60, 'w', 'a' },
|
||||
{ KEY_W, 61, 'b', 'w' },
|
||||
{ KEY_S, 62, 'w', 's' },
|
||||
{ KEY_E, 63, 'b', 'e' },
|
||||
{ KEY_D, 64, 'w', 'd' },
|
||||
{ KEY_F, 65, 'w', 'f' },
|
||||
{ KEY_T, 66, 'b', 't' },
|
||||
{ KEY_G, 67, 'w', 'g' },
|
||||
{ KEY_Y, 68, 'b', 'y' },
|
||||
{ KEY_H, 69, 'w', 'h' },
|
||||
{ KEY_U, 70, 'b', 'u' },
|
||||
{ KEY_J, 71, 'w', 'j' },
|
||||
{ KEY_K, 72, 'w', 'k' },
|
||||
{ KEY_O, 73, 'b', 'o' },
|
||||
{ KEY_L, 74, 'w', 'l' },
|
||||
{ KEY_P, 75, 'b', 'p' },
|
||||
{ KEY_SEMICOLON, 76, 'w', ';' },
|
||||
{ KEY_APOSTROPHE, 77, 'w', '\'' }
|
||||
}, {
|
||||
min = -3, max = 2
|
||||
})
|
||||
min = -3, max = 2
|
||||
} )
|
||||
|
||||
MKeyboard:RegisterLayout('Expanded', {
|
||||
-- key, note, type, label, require SHIFT
|
||||
{KEY_1, 36, 'w', '1'},
|
||||
{KEY_1, 37, 'b', '!', true},
|
||||
{KEY_2, 38, 'w', '2'},
|
||||
{KEY_2, 39, 'b', '@', true},
|
||||
{KEY_3, 40, 'w', '3'},
|
||||
{KEY_4, 41, 'w', '4'},
|
||||
{KEY_4, 42, 'b', '$', true},
|
||||
{KEY_5, 43, 'w', '5'},
|
||||
{KEY_5, 44, 'b', '%', true},
|
||||
{KEY_6, 45, 'w', '6'},
|
||||
{KEY_6, 46, 'b', '^', true},
|
||||
{KEY_7, 47, 'w', '7'},
|
||||
{KEY_8, 48, 'w', '8'},
|
||||
{KEY_8, 49, 'b', '*', true},
|
||||
{KEY_9, 50, 'w', '9'},
|
||||
{KEY_9, 51, 'b', '(', true},
|
||||
{KEY_0, 52, 'w', '0'},
|
||||
MKeyboard:RegisterLayout( 'Expanded', {
|
||||
-- key, note, type, label, require SHIFT
|
||||
{ KEY_1, 36, 'w', '1' },
|
||||
{ KEY_1, 37, 'b', '!', true },
|
||||
{ KEY_2, 38, 'w', '2' },
|
||||
{ KEY_2, 39, 'b', '@', true },
|
||||
{ KEY_3, 40, 'w', '3' },
|
||||
{ KEY_4, 41, 'w', '4' },
|
||||
{ KEY_4, 42, 'b', '$', true },
|
||||
{ KEY_5, 43, 'w', '5' },
|
||||
{ KEY_5, 44, 'b', '%', true },
|
||||
{ KEY_6, 45, 'w', '6' },
|
||||
{ KEY_6, 46, 'b', '^', true },
|
||||
{ KEY_7, 47, 'w', '7' },
|
||||
{ KEY_8, 48, 'w', '8' },
|
||||
{ KEY_8, 49, 'b', '*', true },
|
||||
{ KEY_9, 50, 'w', '9' },
|
||||
{ KEY_9, 51, 'b', '(', true },
|
||||
{ KEY_0, 52, 'w', '0' },
|
||||
|
||||
{KEY_Q, 53, 'w', 'q'},
|
||||
{KEY_Q, 54, 'b', 'Q', true},
|
||||
{KEY_W, 55, 'w', 'w'},
|
||||
{KEY_W, 56, 'b', 'W', true},
|
||||
{KEY_E, 57, 'w', 'e'},
|
||||
{KEY_E, 58, 'b', 'E', true},
|
||||
{KEY_R, 59, 'w', 'r'},
|
||||
{KEY_T, 60, 'w', 't'},
|
||||
{KEY_T, 61, 'b', 'T', true},
|
||||
{KEY_Y, 62, 'w', 'y'},
|
||||
{KEY_Y, 63, 'b', 'Y', true},
|
||||
{KEY_U, 64, 'w', 'u'},
|
||||
{KEY_I, 65, 'w', 'i'},
|
||||
{KEY_I, 66, 'b', 'I', true},
|
||||
{KEY_O, 67, 'w', 'o'},
|
||||
{KEY_O, 68, 'b', 'O', true},
|
||||
{KEY_P, 69, 'w', 'p'},
|
||||
{KEY_P, 70, 'b', 'P', true},
|
||||
{ KEY_Q, 53, 'w', 'q' },
|
||||
{ KEY_Q, 54, 'b', 'Q', true },
|
||||
{ KEY_W, 55, 'w', 'w' },
|
||||
{ KEY_W, 56, 'b', 'W', true },
|
||||
{ KEY_E, 57, 'w', 'e' },
|
||||
{ KEY_E, 58, 'b', 'E', true },
|
||||
{ KEY_R, 59, 'w', 'r' },
|
||||
{ KEY_T, 60, 'w', 't' },
|
||||
{ KEY_T, 61, 'b', 'T', true },
|
||||
{ KEY_Y, 62, 'w', 'y' },
|
||||
{ KEY_Y, 63, 'b', 'Y', true },
|
||||
{ KEY_U, 64, 'w', 'u' },
|
||||
{ KEY_I, 65, 'w', 'i' },
|
||||
{ KEY_I, 66, 'b', 'I', true },
|
||||
{ KEY_O, 67, 'w', 'o' },
|
||||
{ KEY_O, 68, 'b', 'O', true },
|
||||
{ KEY_P, 69, 'w', 'p' },
|
||||
{ KEY_P, 70, 'b', 'P', true },
|
||||
|
||||
{KEY_A, 71, 'w', 'a'},
|
||||
{KEY_S, 72, 'w', 's'},
|
||||
{KEY_S, 73, 'b', 'S', true},
|
||||
{KEY_D, 74, 'w', 'd'},
|
||||
{KEY_D, 75, 'b', 'D', true},
|
||||
{KEY_F, 76, 'w', 'f'},
|
||||
{KEY_G, 77, 'w', 'g'},
|
||||
{KEY_G, 78, 'b', 'G', true},
|
||||
{KEY_H, 79, 'w', 'h'},
|
||||
{KEY_H, 80, 'b', 'H', true},
|
||||
{KEY_J, 81, 'w', 'j'},
|
||||
{KEY_J, 82, 'b', 'J', true},
|
||||
{KEY_K, 83, 'w', 'k'},
|
||||
{KEY_L, 84, 'w', 'l'},
|
||||
{KEY_L, 85, 'b', 'L', true},
|
||||
{ KEY_A, 71, 'w', 'a' },
|
||||
{ KEY_S, 72, 'w', 's' },
|
||||
{ KEY_S, 73, 'b', 'S', true },
|
||||
{ KEY_D, 74, 'w', 'd' },
|
||||
{ KEY_D, 75, 'b', 'D', true },
|
||||
{ KEY_F, 76, 'w', 'f' },
|
||||
{ KEY_G, 77, 'w', 'g' },
|
||||
{ KEY_G, 78, 'b', 'G', true },
|
||||
{ KEY_H, 79, 'w', 'h' },
|
||||
{ KEY_H, 80, 'b', 'H', true },
|
||||
{ KEY_J, 81, 'w', 'j' },
|
||||
{ KEY_J, 82, 'b', 'J', true },
|
||||
{ KEY_K, 83, 'w', 'k' },
|
||||
{ KEY_L, 84, 'w', 'l' },
|
||||
{ KEY_L, 85, 'b', 'L', true },
|
||||
|
||||
{KEY_Z, 86, 'w', 'z'},
|
||||
{KEY_Z, 87, 'b', 'Z', true},
|
||||
{KEY_X, 88, 'w', 'x'},
|
||||
{KEY_C, 89, 'w', 'c'},
|
||||
{KEY_C, 90, 'b', 'C', true},
|
||||
{KEY_V, 91, 'w', 'v'},
|
||||
{KEY_V, 92, 'b', 'V', true},
|
||||
{KEY_B, 93, 'w', 'b'},
|
||||
{KEY_B, 94, 'b', 'B', true},
|
||||
{KEY_N, 95, 'w', 'n'},
|
||||
{KEY_M, 96, 'w', 'm'}
|
||||
{ KEY_Z, 86, 'w', 'z' },
|
||||
{ KEY_Z, 87, 'b', 'Z', true },
|
||||
{ KEY_X, 88, 'w', 'x' },
|
||||
{ KEY_C, 89, 'w', 'c' },
|
||||
{ KEY_C, 90, 'b', 'C', true },
|
||||
{ KEY_V, 91, 'w', 'v' },
|
||||
{ KEY_V, 92, 'b', 'V', true },
|
||||
{ KEY_B, 93, 'w', 'b' },
|
||||
{ KEY_B, 94, 'b', 'B', true },
|
||||
{ KEY_N, 95, 'w', 'n' },
|
||||
{ KEY_M, 96, 'w', 'm' }
|
||||
}, {
|
||||
min = -2, max = 1
|
||||
})
|
||||
min = -2, max = 1
|
||||
} )
|
||||
|
||||
MKeyboard:RegisterLayout('FL Style', {
|
||||
-- key, note, type, label, require SHIFT, alternative key
|
||||
{KEY_Z, 24, 'w', 'z'},
|
||||
{KEY_S, 25, 'b', 's'},
|
||||
{KEY_X, 26, 'w', 'x'},
|
||||
{KEY_D, 27, 'b', 'd'},
|
||||
{KEY_C, 28, 'w', 'c'},
|
||||
{KEY_V, 29, 'w', 'v'},
|
||||
{KEY_G, 30, 'b', 'g'},
|
||||
{KEY_B, 31, 'w', 'b'},
|
||||
{KEY_H, 32, 'b', 'h'},
|
||||
{KEY_N, 33, 'w', 'n'},
|
||||
{KEY_J, 34, 'b', 'j'},
|
||||
{KEY_M, 35, 'w', 'm'},
|
||||
MKeyboard:RegisterLayout( 'FL Style', {
|
||||
-- key, note, type, label, require SHIFT, alternative key
|
||||
{ KEY_Z, 24, 'w', 'z' },
|
||||
{ KEY_S, 25, 'b', 's' },
|
||||
{ KEY_X, 26, 'w', 'x' },
|
||||
{ KEY_D, 27, 'b', 'd' },
|
||||
{ KEY_C, 28, 'w', 'c' },
|
||||
{ KEY_V, 29, 'w', 'v' },
|
||||
{ KEY_G, 30, 'b', 'g' },
|
||||
{ KEY_B, 31, 'w', 'b' },
|
||||
{ KEY_H, 32, 'b', 'h' },
|
||||
{ KEY_N, 33, 'w', 'n' },
|
||||
{ KEY_J, 34, 'b', 'j' },
|
||||
{ KEY_M, 35, 'w', 'm' },
|
||||
|
||||
{KEY_Q, 36, 'w', 'q', false, KEY_COMMA, ','},
|
||||
{KEY_2, 37, 'b', '2', false, KEY_L, 'l'},
|
||||
{KEY_W, 38, 'w', 'w', false, KEY_PERIOD, '.'},
|
||||
{KEY_3, 39, 'b', '3', false, KEY_SEMICOLON, ';'},
|
||||
{KEY_E, 40, 'w', 'e', false, KEY_SLASH, '/'},
|
||||
{KEY_R, 41, 'w', 'r'},
|
||||
{KEY_5, 42, 'b', '5'},
|
||||
{KEY_T, 43, 'w', 't'},
|
||||
{KEY_6, 44, 'b', '6'},
|
||||
{KEY_Y, 45, 'w', 'y'},
|
||||
{KEY_7, 46, 'b', '7'},
|
||||
{KEY_U, 47, 'w', 'u'},
|
||||
{KEY_I, 48, 'w', 'i'},
|
||||
{KEY_9, 49, 'b', '9'},
|
||||
{KEY_O, 50, 'w', 'o'},
|
||||
{KEY_0, 51, 'b', '0'},
|
||||
{KEY_P, 52, 'w', 'p'},
|
||||
{KEY_LBRACKET, 53, 'w', '['},
|
||||
{KEY_EQUAL, 54, 'b', '='},
|
||||
{KEY_RBRACKET, 55, 'w', ']'}
|
||||
{ KEY_Q, 36, 'w', 'q', false, KEY_COMMA, ',' },
|
||||
{ KEY_2, 37, 'b', '2', false, KEY_L, 'l' },
|
||||
{ KEY_W, 38, 'w', 'w', false, KEY_PERIOD, '.' },
|
||||
{ KEY_3, 39, 'b', '3', false, KEY_SEMICOLON, ';' },
|
||||
{ KEY_E, 40, 'w', 'e', false, KEY_SLASH, '/' },
|
||||
{ KEY_R, 41, 'w', 'r' },
|
||||
{ KEY_5, 42, 'b', '5' },
|
||||
{ KEY_T, 43, 'w', 't' },
|
||||
{ KEY_6, 44, 'b', '6' },
|
||||
{ KEY_Y, 45, 'w', 'y' },
|
||||
{ KEY_7, 46, 'b', '7' },
|
||||
{ KEY_U, 47, 'w', 'u' },
|
||||
{ KEY_I, 48, 'w', 'i' },
|
||||
{ KEY_9, 49, 'b', '9' },
|
||||
{ KEY_O, 50, 'w', 'o' },
|
||||
{ KEY_0, 51, 'b', '0' },
|
||||
{ KEY_P, 52, 'w', 'p' },
|
||||
{ KEY_LBRACKET, 53, 'w', '[' },
|
||||
{ KEY_EQUAL, 54, 'b', '=' },
|
||||
{ KEY_RBRACKET, 55, 'w', ']' }
|
||||
}, {
|
||||
min = 0, max = 3
|
||||
})
|
||||
min = 0, max = 3
|
||||
} )
|
File diff suppressed because it is too large
Load Diff
@ -1,105 +1,105 @@
|
||||
resource.AddWorkshop('2656563609')
|
||||
resource.AddWorkshop( '2656563609' )
|
||||
|
||||
util.AddNetworkString('mkeyboard.set_entity')
|
||||
util.AddNetworkString('mkeyboard.notes')
|
||||
util.AddNetworkString( 'mkeyboard.set_entity' )
|
||||
util.AddNetworkString( 'mkeyboard.notes' )
|
||||
|
||||
local function FindBroadcastTargets(pos, radius, filter)
|
||||
-- make the radius squared since we're using DistToSqr (faster)
|
||||
radius = radius * radius
|
||||
local function FindBroadcastTargets( pos, radius, filter )
|
||||
-- make the radius squared since we're using DistToSqr (faster)
|
||||
radius = radius * radius
|
||||
|
||||
local found = {}
|
||||
local found = {}
|
||||
|
||||
for _, v in ipairs(player.GetHumans()) do
|
||||
if v ~= filter and pos:DistToSqr(v:GetPos()) < radius then
|
||||
table.insert(found, v)
|
||||
end
|
||||
end
|
||||
for _, v in ipairs( player.GetHumans() ) do
|
||||
if v ~= filter and pos:DistToSqr( v:GetPos() ) < radius then
|
||||
table.insert( found, v )
|
||||
end
|
||||
end
|
||||
|
||||
return found
|
||||
return found
|
||||
end
|
||||
|
||||
function MKeyboard:IsAMusicalKeyboard(ent)
|
||||
return IsValid(ent) and ent:GetClass() == 'ent_musical_keyboard'
|
||||
function MKeyboard:IsAMusicalKeyboard( ent )
|
||||
return IsValid( ent ) and ent:GetClass() == 'ent_musical_keyboard'
|
||||
end
|
||||
|
||||
function MKeyboard:BroadcastNotes(notes, ent, automated, ignoreTarget)
|
||||
if #notes == 0 then return end
|
||||
function MKeyboard:BroadcastNotes( notes, ent, automated, ignoreTarget )
|
||||
if #notes == 0 then return end
|
||||
|
||||
-- only broadcast to nearby players, if any
|
||||
local targets = FindBroadcastTargets(ent:GetPos(), self.NET_BROADCAST_DISTANCE, ignoreTarget)
|
||||
if #targets == 0 then return end
|
||||
-- only broadcast to nearby players, if any
|
||||
local targets = FindBroadcastTargets( ent:GetPos(), self.NET_BROADCAST_DISTANCE, ignoreTarget )
|
||||
if #targets == 0 then return end
|
||||
|
||||
net.Start('mkeyboard.notes', false)
|
||||
net.WriteEntity(ent)
|
||||
net.WriteBool(automated)
|
||||
net.WriteUInt(#notes, 5)
|
||||
net.Start( 'mkeyboard.notes', false )
|
||||
net.WriteEntity( ent )
|
||||
net.WriteBool( automated )
|
||||
net.WriteUInt( #notes, 5 )
|
||||
|
||||
for _, params in ipairs(notes) do
|
||||
net.WriteUInt(params[1], 7) -- note
|
||||
net.WriteUInt(params[2], 7) -- velocity
|
||||
net.WriteUInt(params[3], 6) -- insrument
|
||||
net.WriteFloat(params[4]) -- time offset
|
||||
end
|
||||
for _, params in ipairs( notes ) do
|
||||
net.WriteUInt( params[1], 7 ) -- note
|
||||
net.WriteUInt( params[2], 7 ) -- velocity
|
||||
net.WriteUInt( params[3], 6 ) -- insrument
|
||||
net.WriteFloat( params[4] ) -- time offset
|
||||
end
|
||||
|
||||
net.Send(targets)
|
||||
net.Send( targets )
|
||||
end
|
||||
|
||||
concommand.Add('keyboard_leave', function(ply, _, args)
|
||||
if #args < 1 then return end
|
||||
local ent = ents.GetByIndex(args[1])
|
||||
concommand.Add( 'keyboard_leave', function( ply, _, args )
|
||||
if #args < 1 then return end
|
||||
local ent = ents.GetByIndex( args[1] )
|
||||
|
||||
if MKeyboard:IsAMusicalKeyboard(ent) and ent.Ply == ply then
|
||||
ent:RemovePlayer()
|
||||
end
|
||||
end)
|
||||
if MKeyboard:IsAMusicalKeyboard( ent ) and ent.Ply == ply then
|
||||
ent:RemovePlayer()
|
||||
end
|
||||
end )
|
||||
|
||||
net.Receive('mkeyboard.notes', function(_, ply)
|
||||
local ent = net.ReadEntity()
|
||||
net.Receive( 'mkeyboard.notes', function( _, ply )
|
||||
local ent = net.ReadEntity()
|
||||
|
||||
-- make sure the client didnt send the wrong entity
|
||||
if not MKeyboard:IsAMusicalKeyboard(ent) then return end
|
||||
-- make sure the client didnt send the wrong entity
|
||||
if not MKeyboard:IsAMusicalKeyboard( ent ) then return end
|
||||
|
||||
local automated = net.ReadBool()
|
||||
local noteCount = net.ReadUInt(5)
|
||||
local notes = {}
|
||||
local automated = net.ReadBool()
|
||||
local noteCount = net.ReadUInt( 5 )
|
||||
local notes = {}
|
||||
|
||||
-- make sure the client isnt tricking us
|
||||
noteCount = math.Clamp(noteCount, 1, MKeyboard.NET_MAX_NOTES)
|
||||
-- make sure the client isnt tricking us
|
||||
noteCount = math.Clamp( noteCount, 1, MKeyboard.NET_MAX_NOTES )
|
||||
|
||||
-- read all notes, to make sure we have as
|
||||
-- many as the client told us on noteCount
|
||||
for i = 1, noteCount do
|
||||
notes[i] = {
|
||||
net.ReadUInt(7), -- note
|
||||
net.ReadUInt(7), -- velocity
|
||||
net.ReadUInt(6), -- instrument
|
||||
math.Clamp(net.ReadFloat(), 0, 1) -- time offset
|
||||
}
|
||||
end
|
||||
-- read all notes, to make sure we have as
|
||||
-- many as the client told us on noteCount
|
||||
for i = 1, noteCount do
|
||||
notes[i] = {
|
||||
net.ReadUInt( 7 ), -- note
|
||||
net.ReadUInt( 7 ), -- velocity
|
||||
net.ReadUInt( 6 ), -- instrument
|
||||
math.Clamp( net.ReadFloat(), 0, 1 ) -- time offset
|
||||
}
|
||||
end
|
||||
|
||||
-- make sure the client is actually using this keyboard
|
||||
if IsValid(ent.Ply) and ply == ent.Ply then
|
||||
-- then broadcast the notes
|
||||
MKeyboard:BroadcastNotes(notes, ent, automated, ply)
|
||||
end
|
||||
end)
|
||||
-- make sure the client is actually using this keyboard
|
||||
if IsValid( ent.Ply ) and ply == ent.Ply then
|
||||
-- then broadcast the notes
|
||||
MKeyboard:BroadcastNotes( notes, ent, automated, ply )
|
||||
end
|
||||
end )
|
||||
|
||||
-- hooks that only run serverside on single-player
|
||||
-- TODO: is there a better way to detect these hooks client-side?
|
||||
if game.SinglePlayer() then
|
||||
util.AddNetworkString('mkeyboard.key')
|
||||
util.AddNetworkString( 'mkeyboard.key' )
|
||||
|
||||
hook.Add('PlayerButtonDown', 'mkeyboard_SPButtonDown', function(ply, button)
|
||||
net.Start('mkeyboard.key', true)
|
||||
net.WriteUInt(button, 8)
|
||||
net.WriteBool(true)
|
||||
net.Send(ply)
|
||||
end)
|
||||
hook.Add( 'PlayerButtonDown', 'mkeyboard_ButtonDownWorkaround', function( ply, button )
|
||||
net.Start( 'mkeyboard.key', true )
|
||||
net.WriteUInt( button, 8 )
|
||||
net.WriteBool( true )
|
||||
net.Send( ply )
|
||||
end )
|
||||
|
||||
hook.Add('PlayerButtonUp', 'mkeyboard_SPButtonUp', function(ply, button)
|
||||
net.Start('mkeyboard.key', true)
|
||||
net.WriteUInt(button, 8)
|
||||
net.WriteBool(false)
|
||||
net.Send(ply)
|
||||
end)
|
||||
hook.Add( 'PlayerButtonUp', 'mkeyboard_ButtonUpWorkaround', function( ply, button )
|
||||
net.Start( 'mkeyboard.key', true )
|
||||
net.WriteUInt( button, 8 )
|
||||
net.WriteBool( false )
|
||||
net.Send( ply )
|
||||
end )
|
||||
end
|
Loading…
Reference in New Issue
Block a user