private async Task ListKits() { if (!await MaybeInitializeMidi()) { return; } inputDevices = string.Join(", ", MidiDevices.ListInputDevices().Select(device => $"{device.SystemDeviceId} ({device.Name})")); outputDevices = string.Join(", ", MidiDevices.ListOutputDevices().Select(device => $"{device.SystemDeviceId} ({device.Name})")); Log("Detecting Roland devices (this can take a few seconds)"); var client = await MidiDevices.DetectSingleRolandMidiClientAsync(logger, ModuleSchema.KnownSchemas.Keys); if (client is object) { await Task.Yield(); var schema = ModuleSchema.KnownSchemas[client.Identifier].Value; Log($"Listing {schema.Identifier.Name} kits:"); var deviceController = new DeviceController(client, NullLogger.Instance); for (int i = 1; i <= schema.Kits; i++) { var name = await deviceController.LoadKitNameAsync(i, CancellationToken.None); Log($"Kit {i}: {name}"); } } }
public async Task <int> InvokeAsync(InvocationContext context) { var console = context.Console.Out; var inputDevices = MidiDevices.ListInputDevices(); string requestedDeviceName = context.ParseResult.ValueForOption <string>("device"); var device = inputDevices.FirstOrDefault(d => d.Name == requestedDeviceName); if (device is null) { console.WriteLine($"Device '{requestedDeviceName}' not found."); var names = string.Join(", ", inputDevices.Select(d => $"'{d.Name}'")); console.WriteLine($"Available devices: {names}"); return(1); } // It's slightly annoying to use the underlying MIDI implementation rather than RawMidiClient, but we can always change // it if necessary, and RawMidiClient expects input *and* output (and is currently internal). using (var input = await MidiDevices.Manager.OpenInputAsync(device)) { console.WriteLine($"Listening for one minute - or press Ctrl-C to quit."); input.MessageReceived += DisplayMessage; // Wait for one minute - or until the user kills the process. await Task.Delay(TimeSpan.FromMinutes(1)); } return(0); void DisplayMessage(object sender, MidiMessage message) => console.WriteLine($"Received: {BitConverter.ToString(message.Data)}"); }
static async Task Main(string[] args) { // Just so we can write synchronous code when we want to await Task.Yield(); try { var inputs = MidiDevices.ListInputDevices(); foreach (var input in inputs) { Console.WriteLine($"Input: {input}"); } var outputs = MidiDevices.ListOutputDevices(); foreach (var output in outputs) { Console.WriteLine($"Output: {output}"); } var td17Input = inputs.Single(input => input.Name == "2- TD-17"); var td17Output = outputs.Single(output => output.Name == "2- TD-17"); var identities = await MidiDevices.ListDeviceIdentities(td17Input, td17Output, TimeSpan.FromSeconds(0.5)); foreach (var identity in identities) { Console.WriteLine(identity); } } catch (Exception e) { Console.WriteLine(e); } }
internal static async Task <(RolandMidiClient client, ModuleSchema schema)> DetectDeviceAsync(IStandardStreamWriter console) { var inputDevices = MidiDevices.ListInputDevices(); var outputDevices = MidiDevices.ListOutputDevices(); var commonNames = inputDevices.Select(input => input.Name) .Intersect(outputDevices.Select(output => output.Name)) .OrderBy(x => x) .ToList(); if (commonNames.Count != 1) { console.WriteLine("Error: No input and output MIDI ports with the same name detected."); return(null, null); } string name = commonNames[0]; var matchedInputs = inputDevices.Where(input => input.Name == name).ToList(); var matchedOutputs = outputDevices.Where(output => output.Name == name).ToList(); if (matchedInputs.Count != 1 || matchedOutputs.Count != 1) { console.WriteLine($"Error: Name {name} matches multiple input or output MIDI ports."); return(null, null); } var identities = await MidiDevices.ListDeviceIdentities(matchedInputs[0], matchedOutputs[0], TimeSpan.FromSeconds(1)); if (identities.Count != 1) { console.WriteLine($"Error: {(identities.Count == 0 ? "No" : "Multiple")} devices detected for MIDI port {name}."); return(null, null); } var schemaKeys = SchemaRegistry.KnownSchemas.Keys; var identity = identities[0]; var matchingKeys = schemaKeys.Where(sk => sk.FamilyCode == identity.FamilyCode && sk.FamilyNumberCode == identity.FamilyNumberCode).ToList(); if (matchingKeys.Count != 1) { console.WriteLine($"Error: {(matchingKeys.Count == 0 ? "No" : "Multiple")} schemas detected for MIDI device."); return(null, null); } var schema = SchemaRegistry.KnownSchemas[matchingKeys[0]]; var moduleIdentifier = schema.Value.Identifier; var client = await MidiDevices.CreateRolandMidiClientAsync(matchedInputs[0], matchedOutputs[0], identity, moduleIdentifier.ModelId); return(client, schema.Value); }
public async Task <int> InvokeAsync(InvocationContext context) { var console = context.Console.Out; console.WriteLine("Input devices:"); var inputDevices = MidiDevices.ListInputDevices(); foreach (var device in inputDevices) { console.WriteLine($"{device.SystemDeviceId}: {device.Name}"); } console.WriteLine(); console.WriteLine("Output devices:"); var outputDevices = MidiDevices.ListOutputDevices(); foreach (var device in outputDevices) { console.WriteLine($"{device.SystemDeviceId}: {device.Name}"); } console.WriteLine(); var commonNames = inputDevices.Select(input => input.Name) .Intersect(outputDevices.Select(output => output.Name)) .OrderBy(x => x) .ToList(); foreach (var name in commonNames) { var matchedInputs = inputDevices.Where(input => input.Name == name).ToList(); var matchedOutputs = outputDevices.Where(output => output.Name == name).ToList(); if (matchedInputs.Count != 1 || matchedOutputs.Count != 1) { continue; } console.WriteLine($"Detecting device identities for {name}..."); var identities = await MidiDevices.ListDeviceIdentities(matchedInputs[0], matchedOutputs[0], TimeSpan.FromSeconds(1)); foreach (var identity in identities) { console.WriteLine(identity.ToString()); } console.WriteLine(); } return(0); }
public async Task <int> InvokeAsync(InvocationContext context) { var console = context.Console.Out; var inputDevices = MidiDevices.ListInputDevices(); string inputName = context.ParseResult.ValueForOption <string>("input"); var inputDevice = inputDevices.FirstOrDefault(d => d.Name == inputName); if (inputDevice is null) { console.WriteLine($"Input device '{inputName}' not found."); return(1); } var outputDevices = MidiDevices.ListOutputDevices(); string outputName = context.ParseResult.ValueForOption <string>("output"); var outputDevice = outputDevices.FirstOrDefault(d => d.Name == outputName); if (outputDevice is null) { console.WriteLine($"Output device '{outputName}' not found."); return(1); } int inputChannel = context.ParseResult.ValueForOption <int>("inputChannel"); int outputChannel = context.ParseResult.ValueForOption <int>("outputChannel"); using var input = await MidiDevices.Manager.OpenInputAsync(inputDevice); using var output = await MidiDevices.Manager.OpenOutputAsync(outputDevice); console.WriteLine("Proxying"); input.MessageReceived += (sender, message) => { var type = message.Status & 0xf0; switch (type) { case 0b1000_0000: // Note off case 0b1001_0000: // Note on case 0b1010_0000: // Polyphonic key pressure (aftertouch) case 0b1101_0000: // Channel pressure (aftertouch) case 0b1110_0000: // Pitch bench change if ((message.Status & 0xf) == inputChannel) { message.Data[0] = (byte)(type | outputChannel); } output.Send(message); break; case 0b1011: // Control change case 0b1100: // Program change case 0b1111: // System exclusive break; } }; // Effectively "forever unless I forget to turn things off". await Task.Delay(TimeSpan.FromHours(1)); return(0); }