Arte abstrata high-tech de um mapa JSON traduzindo comandos MIDI em ações e feedback luminoso do WAVESampler

O SDK MIDI do WAVESampler é o contrato técnico usado para integrar superfícies de controle ao aplicativo por meio de mapas JSON declarativos. O arquivo descreve a topologia do hardware, as mensagens recebidas e enviadas, a compatibilidade das portas, as ações semânticas do WAVESampler e a tradução do estado visual para LEDs, paletas ou mensagens SysEx.

Configurações de controladores MIDI do WAVESampler, com seleção independente de entrada, saída e mapeamento
A página de Controladores MIDI conecta MIDI IN e MIDI OUT separadamente e ativa um mapa JSON compatível.

Escopo e princípios do SDK

Um controlador é integrado adicionando um único arquivo .json à pasta de mapas. Não há código executável no mapa, chamadas a controles WPF, scripts, assemblies, URLs, expressões arbitrárias ou lógica específica de fabricante. O hardware é traduzido para ações estáveis; o estado do WAVESampler é traduzido de volta para as capacidades reais da superfície.

  • Mapas são dados: um novo equipamento não exige recompilar o WAVESampler.
  • Entrada e saída são independentes: MIDI IN pode executar ações sem MIDI OUT; MIDI OUT pode renderizar estado sem entrada.
  • Ativação é atômica: o documento inteiro é desserializado, validado e compilado antes de se tornar ativo.
  • Áudio continua no BASS: o MIDI apenas encaminha intenção e valores para os serviços existentes.
  • A interface é soberana: cores e estados finais vêm do mesmo provedor de aparência usado pelo WAVESampler; o JSON descreve como o hardware consegue representá-los.

Arquitetura do runtime

Catálogo e watcher de dispositivos Windows
              ↓
Gerenciador independente de MIDI IN e MIDI OUT
              ↓
Backend de transporte NAudio 2.3.0
              ↓
Normalização: press | release | change
              ↓
Mapa validado e compilado em tabelas imutáveis
              ↓
Dispatcher de ações semânticas
      ↙               ↓                 ↘
  Sampler           Mixer             Playlist
      ↓               ↓                 ↓
Serviços do WAVESampler e execução de áudio BASS
              ↓
Provedor soberano de aparência
              ↓
Tradução on/off | brilho | paleta | RGB | SysEx
              ↓
            MIDI OUT

Os callbacks MIDI não leem arquivos, não interpretam JSON e não acessam diretamente a árvore visual. O mapa ativo já contém uma tabela de entrada indexada por (tipo de mensagem, canal, número). Eventos normalizados são enviados ao dispatcher; alterações de estado retornam ao renderer de feedback, que elimina mensagens duplicadas antes de escrever na saída.

Localização, descoberta e ciclo de ativação

Os mapas são procurados somente no primeiro nível da pasta:

<Pasta de documentos configurada no WAVESampler>MidiMaps*.json
  • A pasta é criada automaticamente quando o catálogo é consultado.
  • Os arquivos são ordenados pelo nome do arquivo; documentos inválidos permanecem diagnosticáveis pelo nome e pela mensagem de erro.
  • A instalação não fornece mapas automaticamente. Copiar, renomear, editar e remover arquivos é responsabilidade do usuário ou integrador.
  • A lista é examinada quando a página MIDI é inicializada. Nesta versão não existem Importar, Exportar, Learn, Testar ou Mapping Studio.
  • Selecionar uma porta não a abre. As conexões são manuais pelos botões Conectar e Tentar novamente.

Ao trocar o mapa, o runtime valida e compila o novo documento, libera gestos pressionados, envia a desativação anterior quando possível, ativa o novo mapa, executa sua inicialização se MIDI OUT estiver conectado e renderiza a superfície completa. Um mapa inválido deixa as portas utilizáveis, mas não executa bindings, inicialização ou feedback.

Regras gerais do JSON

O formato atual aceita exclusivamente schemaVersion: 1. Propriedades desconhecidas nas classes tipadas são rejeitadas. Os objetos capabilities e target são deliberadamente abertos, embora somente os campos reconhecidos pelo runtime produzam comportamento.

Campo raizObrigatórioTipo e regra
schemaVersionSimInteiro. Deve ser exatamente 1.
idSimTexto não vazio e estável. Recomenda-se namespace reverso: fabricante.modelo.wavesampler.variante.
nameSimNome exibido na lista de mapeamentos.
descriptionNãoDescrição humana do mapa.
authorNãoAutor ou organização responsável.
controllerSimPerfil físico, endpoints, controles e feedback.
mappingSimLista de bindings entre controles e ações.

Objeto controller

CampoTipoFunção
manufacturerstringFabricante, para documentação e diagnóstico.
modelstringModelo ou família do equipamento.
deviceMatchobjectPadrões de compatibilidade separados por direção.
capabilitiesobject abertoMetadados técnicos do hardware. Atualmente não habilitam funções nem substituem a validação dos controles.
inputDefaultsobjectDefaults de entrada; atualmente contém note.release.
feedbackDefaultsobjectModelo de feedback herdado por controles que não declaram feedback próprio.
initializationarrayMensagens enviadas após mapa válido e MIDI OUT conectado.
deactivationarrayMensagens best-effort em troca de mapa, desconexão intencional ou desligamento.
controlsarrayObrigatório e não vazio. Declara todos os controles físicos conhecidos pelo mapa.

Compatibilidade de endpoints: deviceMatch

"deviceMatch": {
  "inputNamePatterns": [
    "*Launchpad Mini MK3*",
    "*Launchpad MIDI IN*"
  ],
  "outputNamePatterns": [
    "*Launchpad Mini MK3*",
    "*Launchpad MIDI OUT*"
  ]
}

Os padrões são comparados ao nome visível do endpoint sem diferenciar maiúsculas de minúsculas. O caractere * representa qualquer sequência. Uma coleção vazia aceita qualquer dispositivo naquela direção. Pelo menos um endpoint deve estar selecionado e todos os endpoints selecionados precisam corresponder ao mapa.

Não trate portas MIDI, DAW e DIN como equivalentes. Alguns controladores expõem diversos pares. O padrão deve selecionar a porta que realmente envia o protocolo descrito no mapa. A identidade persistida do dispositivo usa endpoint, direção, nome, fabricante e produto; deviceMatch é uma regra de compatibilidade, não a identidade física persistida.

Capabilities

capabilities aceita um objeto JSON livre. O mapa de referência usa chaves como noteInput, controlChangeInput, pitchBendInput, velocity, polyAftertouch, channelPressure, sysExInput, sysExOutput, absoluteControls e relativeEncoders. Elas documentam o perfil; o runtime atual não consulta esse objeto. O comportamento efetivo é determinado por controls, bindings e pela validação.

Defaults de liberação

"inputDefaults": {
  "note": {
    "release": "either"
  }
}

A resolução ocorre na ordem control.input.releasecontroller.inputDefaults.note.release → sem suporte. Valores:

  • noteOff: o equipamento envia Note Off explícito.
  • noteOnZero: a liberação é Note On com velocity zero.
  • either: aceita ambas as formas MIDI padrão.
  • value: um controle não-note usa valores declarados em releasedValues.
  • none: não existe evento físico de soltura.

Objeto control

Cada item de controller.controls representa um controle físico ou uma saída endereçável. IDs duplicados são rejeitados. Também é proibido declarar dois controles com a mesma chave de entrada normalizada — mesmo tipo, canal e número.

CampoObrigatórioSemântica
idSimIdentidade técnica local, referenciada por mapping.bindings[].control.
kindNãoTexto descritivo; padrão button. Exemplos do mapa: button, velocityPad, fader, relativeEncoder. Atualmente não altera a execução.
positionNão{row, column}; metadado topológico, não usado para localizar bindings.
inputNãoMensagem recebida pelo controle.
outputNãoEndereço MIDI usado para feedback de valor curto ou como presença de saída para templates.
feedbackNãoSobrescreve feedbackDefaults para este controle.

Configuração de input

CampoTipo / padrãoDetalhe
messagestring, obrigatórionote, noteOn, noteOff, controlChange, pitchBend, polyAftertouch, channelPressure, systemExclusive ou sysEx. Note On/Off são normalizados como note; SysEx como systemExclusive.
channel1–16; padrão 1Canal MIDI. Para mensagens sem número, ainda participa da definição, embora a chave de runtime use número -1.
number0–127Obrigatório para note, Control Change e poly aftertouch. É a nota ou número do controlador.
releasestringnoteOff, noteOnZero, either, value ou none.
modestringabsolute ou relativeBinaryOffset.
minimumValue0–127; padrão 0Limite inferior declarado da entrada.
maximumValue0–127; padrão 127Limite superior; não pode ser menor que o mínimo.
pressedValuesarray 0–127Valores de CC convertidos em evento press.
releasedValuesarray 0–127Valores de CC convertidos em release. Obrigatório quando release: value.
neutralValue0–127Centro obrigatório de relativeBinaryOffset. O delta atual é valor - neutralValue.
decrementRange{minimum, maximum}Faixa válida que documenta valores de decremento do encoder relativo.
incrementRange{minimum, maximum}Faixa válida que documenta valores de incremento. Ambas as faixas são obrigatórias e validadas no modo relativo.
{
  "id": "encoder-volume",
  "kind": "relativeEncoder",
  "input": {
    "message": "controlChange",
    "channel": 1,
    "number": 16,
    "mode": "relativeBinaryOffset",
    "neutralValue": 64,
    "decrementRange": { "minimum": 1, "maximum": 63 },
    "incrementRange": { "minimum": 65, "maximum": 127 }
  }
}

Note On com velocity maior que zero gera press; velocity zero gera release quando permitido. Note Off gera release. CC usa primeiro pressedValues/releasedValues; os demais valores geram change. Pitch bend produz valor de 14 bits e delta em torno de 8192. Aftertouch e pressão de canal geram change. SysEx recebido é normalizado como mudança, mas o mapa schema 1 não possui comparação de payload: existe uma única chave global de entrada SysEx.

Configuração de output

"output": {
  "message": "noteOn",
  "channel": 1,
  "number": 36
}

output.message aceita noteOn, noteOff, controlChange ou systemExclusive; channel aceita 1–16; number é obrigatório e limitado a 0–127 para mensagens curtas. Modos onOff, brightness e indexedPalette devem usar uma mensagem curta com número. Para rgb e deviceSpecific, a mensagem efetiva vem do template SysEx de feedback.

Feedback: campos e modos

O controle usa seu próprio objeto feedback; se ele não existir, herda controller.feedbackDefaults. Sem ambos, ou com mode: none, nada é enviado.

CampoRegra
modenone, onOff, brightness, indexedPalette, rgb ou deviceSpecific.
minimumValue / maximumValueFaixa 0–127 usada para escalar brilho.
offValue / onValueValores 0–127 usados por onOff.
fixedColorCor física #RRGGBB, útil como metadado de LED monocromático. Atualmente não substitui a aparência soberana.
supportsBlinkDeclara suporte nativo a piscar. Quando falso e a UI solicita blink, o runtime registra degradação e envia estado sólido.
supportsPulseMesmo comportamento para pulse.
paletteDicionário índice 0–127 → cor #RRGGBB. Obrigatório em indexedPalette.
templateMensagem SysEx obrigatória para rgb e deviceSpecific.
  • none: ignora feedback.
  • onOff: envia offValue quando apagado e onValue quando aceso/ativo.
  • brightness: converte brilho normalizado para minimumValue..maximumValue.
  • indexedPalette: converte a cor sRGB para CIE Lab e escolhe o menor Delta E 76; empates escolhem o menor índice.
  • rgb: expande um template SysEx com componentes de cor.
  • deviceSpecific: usa o mesmo mecanismo seguro de template para um protocolo proprietário delimitado.
"feedback": {
  "mode": "rgb",
  "minimumValue": 0,
  "maximumValue": 127,
  "supportsBlink": false,
  "supportsPulse": false,
  "template": {
    "send": "sysEx",
    "data": "F0 7D 57 53 {r} {g} {b} {brightness} F7"
  }
}

Os placeholders aceitos no template atual são exclusivamente {r}, {g}, {b} e {brightness}. Depois da substituição, a sequência precisa conter bytes hexadecimais separados por espaços, começar em F0 e terminar em F7. Qualquer placeholder desconhecido rejeita o mapa.

Inicialização e desativação

initialization e deactivation aceitam operações declarativas:

sendCampos
noteOnchannel 1–16, number 0–127, value 0–127.
noteOffMesmos campos de mensagem curta.
controlChangeCanal, número do CC e valor.
sysExdata como bytes hexadecimais completos de F0 a F7.
"initialization": [
  { "send": "sysEx", "data": "F0 7D 57 53 01 01 F7" },
  { "send": "controlChange", "channel": 1, "number": 0, "value": 1 }
],
"deactivation": [
  { "send": "controlChange", "channel": 1, "number": 0, "value": 0 },
  { "send": "sysEx", "data": "F0 7D 57 53 01 00 F7" }
]

Objeto mapping e bindings

mapping.bindings é obrigatório. A lista pode estar vazia, mas então nenhum comando será executado. Vários bindings podem referenciar o mesmo controle e todos os eventos compatíveis serão despachados. Para feedback, o renderer usa o primeiro binding do controle como fonte visual; portanto coloque primeiro a ação cuja aparência o LED deve espelhar.

CampoObrigatórioFunção
controlSimID exato de um item em controller.controls.
onNãopress, release, change ou gesture. O padrão é gesture para sampler.key e press para as demais ações. gesture é reservado ao gesto completo de sampler key.
actionSimIdentificador semântico listado abaixo.
targetDepende da açãoObjeto aberto validado conforme a família da ação.
velocityNãoCurva de velocity; permitida somente em sampler.key e sampler.key.trigger.
transformNãoTransforma valor absoluto ou delta relativo antes do dispatcher.

Velocity

"velocity": {
  "target": "triggerVolumeMultiplier",
  "curve": "soft",
  "minimum": 0.20,
  "maximum": 1.0
}

target deve ser triggerVolumeMultiplier. curve aceita linear, soft (raiz quadrada) ou hard (quadrado). Mínimo e máximo precisam ser finitos, ordenados e contidos em 0–1. O resultado é um multiplicador transitório aplicado antes do início do stream; ele não altera volumes persistidos.

Transform de valores

"transform": {
  "inputMinimum": 0,
  "inputMaximum": 127,
  "outputMinimum": 0.0,
  "outputMaximum": 1.0
}

Sem transform, um evento change entrega o valor bruto. Com transformação absoluta, o runtime interpola a entrada e limita o resultado à faixa de saída. inputMinimum e inputMaximum não podem ser iguais; valores devem ser finitos; a saída deve estar ordenada.

"transform": {
  "inputMinimum": 0,
  "inputMaximum": 127,
  "outputMinimum": -1.0,
  "outputMaximum": 1.0,
  "step": 0.01
}

Quando step existe, a saída é relativeDelta × step. O passo deve ser finito e maior que zero. Essa forma é apropriada para ações .adjust com encoder relativo.

Ações do sampler

AçãoTargetUso
sampler.key{"pad":"current"|0..6,"key":"D1"}Gesto completo de key down/key up. Exige liberação real.
sampler.key.triggerMesmo targetDisparo one-shot para controles sem release; não participa do latch de Hold Key.
sampler.pad.select{"pad":0..6}Seleciona o pad visível.
sampler.stop{"scope":"allSamplerChannels"}Para todos os canais de sampler.
sampler.stop{"channel":1..3}Para um canal de sampler.
sampler.stop{"pad":"current"|0..6,"key":"D1"}Para uma tecla concreta.
sampler.reloop.downVazioInicia o gesto de replay/reloop.
sampler.reloop.upVazioFinaliza o gesto.

key deve ser um nome válido de System.Windows.Input.Key, como D1 ou A, e precisa corresponder a uma posição reconhecida pelo sampler. pad: current é resolvido no momento do press e capturado como (SamplerPad, Key). Se o usuário trocar de pad antes da liberação, o release continua destinado ao botão original. Um número fixa o controle naquele pad, mesmo quando outro está visível.

Ao desativar MIDI, desconectar a entrada ou trocar o mapa, todos os sampler.key ainda pressionados são liberados pelo runtime. Isso impede Hold Key preso após perda de conexão. Um controle com release: none não pode usar sampler.key nem um binding on: release; use sampler.key.trigger.

Ações do mixer

Toda ação mixer.* requer target.channel igual a 1, 2, 3, 4 ou "master". A validação aceita todos esses alvos; o serviço do mixer aplica somente recursos existentes naquele strip.

GrupoAçõesValor
Volumemixer.volume.set
mixer.volume.adjust
Absoluto ou delta transformado.
Pitchmixer.pitch.set
mixer.pitch.adjust
Absoluto ou delta.
Panmixer.pan.set
mixer.pan.adjust
Absoluto ou delta.
Ativaçãomixer.enabled.set
mixer.enabled.toggle
Booleano.
Lock de volumemixer.volumeLock.set
mixer.volumeLock.toggle
Booleano.
Lock de pitchmixer.pitchLock.set
mixer.pitchLock.toggle
Booleano.
Lock de panmixer.panLock.set
mixer.panLock.toggle
Booleano.
Hold Keymixer.holdKey.set
mixer.holdKey.toggle
Booleano.
Reloopmixer.reloop.set
mixer.reloop.toggle
Booleano.
Sampler Delaymixer.samplerDelay.set
mixer.samplerDelay.toggle
Booleano.
Equalizadormixer.equalizer.set
mixer.equalizer.toggle
Booleano.
Efeitosmixer.effects.set
mixer.effects.toggle
Booleano.
Multisamplingmixer.multiSampling.set
mixer.multiSampling.toggle
Booleano.

Em ações .set, o booleano vem do valor transformado (>= 0.5) ou de target.value; quando ambos faltam, o padrão é true. Ações .toggle ignoram valor. Ações .adjust são relativas; use step para controlar a sensibilidade.

{
  "control": "channel-1-volume",
  "on": "change",
  "action": "mixer.volume.set",
  "target": { "channel": 1 },
  "transform": {
    "inputMinimum": 0,
    "inputMaximum": 127,
    "outputMinimum": 0.0,
    "outputMaximum": 1.0
  }
}

Ações da playlist e Canal 4

AçãoTarget / valor
playlist.playSelectedReproduz o item selecionado.
playlist.pauseResumeAlterna pausa e retomada.
playlist.stopPara a reprodução.
playlist.selectPreviousSeleciona o item anterior.
playlist.selectNextSeleciona o próximo.
playlist.selectIndextarget.index >= 0 ou valor fornecido por transform; o resultado é arredondado.
playlist.playPreviousReproduz o item anterior.
playlist.playNextReproduz o próximo item.
playlist.position.setValor contínuo, normalmente transformado para 0–1.
playlist.add.openDialogAbre o fluxo existente de adicionar arquivos.
playlist.removeSelectedRemove itens selecionados.
playlist.clearLimpa a playlist pelo serviço compartilhado.
playlist.moveSelectedUpMove a seleção para cima.
playlist.moveSelectedDownMove a seleção para baixo.
playlist.playerMode.setBooleano transformado ou target.value; padrão true.
playlist.playerMode.toggleAlterna o modo Player.

Essas ações passam pelo mesmo serviço usado pela interface do player. Elas não simulam cliques nem chamam handlers privados; por isso preservam validações, seleção, estado sujo e comportamento do Canal 4.

Exemplo integrado

{
  "schemaVersion": 1,
  "id": "acme.grid.wavesampler.standard",
  "name": "ACME Grid - WAVESampler",
  "description": "Pad com velocity, encoder relativo e LED por paleta.",
  "author": "ACME",
  "controller": {
    "manufacturer": "ACME",
    "model": "Grid",
    "deviceMatch": {
      "inputNamePatterns": ["*ACME Grid MIDI IN*"],
      "outputNamePatterns": ["*ACME Grid MIDI OUT*"]
    },
    "capabilities": {
      "noteInput": true,
      "controlChangeInput": true,
      "velocity": true,
      "relativeEncoders": true
    },
    "inputDefaults": {
      "note": { "release": "either" }
    },
    "feedbackDefaults": {
      "mode": "indexedPalette",
      "minimumValue": 0,
      "maximumValue": 127,
      "offValue": 0,
      "onValue": 127,
      "supportsBlink": true,
      "supportsPulse": false,
      "palette": {
        "0": "#000000",
        "5": "#FF0000",
        "21": "#00FF00",
        "45": "#0000FF",
        "69": "#FFFFFF"
      }
    },
    "initialization": [
      { "send": "sysEx", "data": "F0 7D 01 01 F7" }
    ],
    "deactivation": [
      { "send": "sysEx", "data": "F0 7D 01 00 F7" }
    ],
    "controls": [
      {
        "id": "sample-d1",
        "kind": "velocityPad",
        "position": { "row": 1, "column": 0 },
        "input": {
          "message": "note",
          "channel": 1,
          "number": 36,
          "release": "either"
        },
        "output": {
          "message": "noteOn",
          "channel": 1,
          "number": 36
        }
      },
      {
        "id": "volume-1",
        "kind": "relativeEncoder",
        "input": {
          "message": "controlChange",
          "channel": 1,
          "number": 16,
          "mode": "relativeBinaryOffset",
          "neutralValue": 64,
          "decrementRange": { "minimum": 1, "maximum": 63 },
          "incrementRange": { "minimum": 65, "maximum": 127 }
        }
      },
      {
        "id": "play",
        "kind": "button",
        "input": {
          "message": "controlChange",
          "channel": 1,
          "number": 40,
          "release": "value",
          "pressedValues": [127],
          "releasedValues": [0]
        },
        "output": {
          "message": "controlChange",
          "channel": 1,
          "number": 40
        },
        "feedback": {
          "mode": "onOff",
          "offValue": 0,
          "onValue": 127
        }
      }
    ]
  },
  "mapping": {
    "bindings": [
      {
        "control": "sample-d1",
        "action": "sampler.key",
        "target": { "pad": "current", "key": "D1" },
        "velocity": {
          "target": "triggerVolumeMultiplier",
          "curve": "linear",
          "minimum": 0.20,
          "maximum": 1.0
        }
      },
      {
        "control": "volume-1",
        "on": "change",
        "action": "mixer.volume.adjust",
        "target": { "channel": 1 },
        "transform": {
          "inputMinimum": 0,
          "inputMaximum": 127,
          "outputMinimum": -1.0,
          "outputMaximum": 1.0,
          "step": 0.01
        }
      },
      {
        "control": "play",
        "on": "press",
        "action": "playlist.playSelected",
        "target": {}
      }
    ]
  }
}

Validações que rejeitam o mapa

  • JSON inválido, documento vazio, propriedade desconhecida em um modelo tipado ou versão diferente de 1.
  • id/name vazios, zero controles, IDs duplicados ou binding apontando para controle inexistente.
  • Dois controles usando a mesma combinação normalizada de mensagem, canal e número.
  • Canal fora de 1–16, byte de dados fora de 0–127, faixa invertida ou SysEx sem F0 ... F7.
  • Mensagem, release, modo, evento, ação ou feedback desconhecido.
  • release: value sem releasedValues, ou ação release-aware em controle sem liberação.
  • Target de sampler, mixer ou playlist fora dos limites descritos acima.
  • Velocity em ação que não seja sampler key, curva desconhecida ou limites fora de 0–1.
  • Transform não finito, faixa de entrada sem amplitude, saída invertida ou step <= 0.
  • Paleta vazia, cor que não seja #RRGGBB, índice fora de 0–127 ou template SysEx inválido.

Feedback soberano e atualização da superfície

Bindings não declaram cores de standby, pressed, playing, active ou locked. O provedor de aparência entrega ao MIDI um snapshot imutável, como isLit, cor resolvida, brilho, efeito e valor normalizado. Assim, mudanças de tema, pad, reprodução, mixer e playlist chegam ao hardware sem duplicar regras visuais no JSON.

Uma renderização completa ocorre quando um mapa válido é ativado, quando MIDI OUT conecta ou quando há refresh visual global. Mudanças específicas renderizam somente controles afetados. Controles ligados a pad: current são todos recalculados quando o pad muda. Mensagens idênticas à última mensagem do mesmo controle são coalescidas.

Diagnóstico, desempenho e limites

  • Logs operacionais registram descoberta, validação, troca de endpoint, conexão, inicialização, degradação de feedback e erros de transporte.
  • Tráfego Note/CC de alta frequência não deve gerar log normal por evento.
  • Erros de ação são isolados ao evento; não fecham conexões saudáveis nem interrompem o BASS.
  • Erro de saída suspende feedback até reconexão, sem parar MIDI IN.
  • O SDK schema 1 suporta uma entrada e uma saída simultâneas, não múltiplas portas por direção.
  • Não inclui MIDI clock, sequenciamento, MPE, playback de arquivo MIDI, síntese BASSMIDI, DAW control genérico, editor de mapas ou learn mode.
  • Não importa keymaps, não edita samples e não abre editores por binding.

Checklist de entrega de um mapa

  1. Use um id estável e mantenha schemaVersion: 1.
  2. Meça os nomes reais das portas e diferencie MIDI, DAW e DIN.
  3. Documente cada mensagem física, inclusive a forma verdadeira de release.
  4. Use sampler.key.trigger quando não existir soltura.
  5. Teste valores mínimos, máximos, neutros, curvas de velocity e sensibilidade de encoders.
  6. Teste MIDI IN sem OUT, OUT sem IN e falhas independentes.
  7. Teste mudança de pad durante uma tecla pressionada e bindings para pads fixos.
  8. Teste troca de tema, playback, mixer e playlist para validar o feedback soberano.
  9. Desconecte o equipamento durante Hold Key e confirme que o estado pressionado é limpo.
  10. Coloque o JSON em MidiMaps, reabra a página, selecione as portas, conecte-as manualmente e escolha o mapa compatível.

Para a operação diária da página de configurações, consulte Controladores MIDI — Mapeamento do controlador.

Comments

Deixe um comentário

O seu endereço de e-mail não será publicado. Campos obrigatórios são marcados com *