internal IEnumerable <IContainer> ToContainers(ModuleSchema schema, ModuleJson module, ModuleAddress parentAddress, string?parentPath, SchemaVariables variables)
        {
            variables = variables.WithVariables(ExtraVariables);
            ModuleOffset offset = ModuleOffset.FromDisplayValue(Offset.Value);

            if (Repeat is null)
            {
                yield return(resolvedContainer.ToContainer(schema, module, ResolvedName, ResolvedDescription,
                                                           parentAddress + offset, parentPath, variables));
            }
            else
            {
                int gap = ModuleOffset.FromDisplayValue(Repeat.Gap.Value).LogicalValue;
                foreach (var tuple in module.GetRepeatSequence(Repeat.Items, variables))
                {
                    var itemVariables        = variables.WithVariable(Repeat.IndexVariable, tuple.index, Repeat.IndexTemplate);
                    var formattedDescription = tuple.variables.Replace(ResolvedDescription);
                    var formattedName        = Invariant($"{ResolvedName}[{tuple.index}]");
                    yield return(resolvedContainer.ToContainer(schema, module, formattedName, formattedDescription,
                                                               parentAddress + offset, parentPath, itemVariables));

                    offset += gap;
                }
            }
        }
Example #2
0
 private IField ToField(ModuleSchema schema, ModuleJson module, string name, int offset, string description, FieldCondition?condition)
 {
     // TODO: Validate that we don't have "extra" parameters?
     return(Type switch
     {
         "boolean" => (IField) new BooleanField(BuildCommon(1)),
         "boolean32" => new BooleanField(BuildCommon(4)),
         "range8" => BuildNumericField(1),
         "range16" => BuildNumericField(2),
         "range32" => BuildNumericField(4),
         "enum" => BuildEnumField(1),
         "enum16" => BuildEnumField(2),
         "enum32" => BuildEnumField(4),
         "dynamicOverlay" => BuildDynamicOverlay(),
         "instrument" => new InstrumentField(BuildCommon(4),
                                             ValidateNotNull(BankOffset, nameof(BankOffset)).Value,
                                             ValidateNotNull(VeditOffset, nameof(VeditOffset)).Value),
         "musicalNote" => new EnumField(BuildCommon(4), MusicalNoteValues, 0, 0),
         "volume32" => new NumericField(BuildCommon(4), -601, 60, 0, 10, null, 0, "dB", (-601, "-INF")),
         "string" => BuildStringField(1),
         "string16" => BuildStringField(2),
         "midi32" => new MidiNoteField(BuildCommon(4)),
         string text when text.StartsWith(ContainerPrefix) => BuildContainer(),
         _ => throw new InvalidOperationException($"Unknown field type: {Type}")
     });
Example #3
0
 internal DeviceLoaderDialog(ILogger logger, RolandMidiClient client, ModuleSchema schema) : this()
 {
     this.logger             = logger;
     this.client             = client;
     this.schema             = schema;
     cancellationTokenSource = new CancellationTokenSource(TimeSpan.FromMinutes(10));
 }
Example #4
0
        internal Audio.InstrumentAudio ToModel(ModuleSchema schema)
        {
            var bank       = Preset ? schema.PresetInstruments : schema.UserSampleInstruments;
            var instrument = bank[InstrumentId];

            return(new Audio.InstrumentAudio(instrument, AudioData.ToByteArray()));
        }
        internal SoundRecorderDialog(ILogger logger, ModuleSchema schema, RolandMidiClient midiClient)
            : this()
        {
            this.logger                   = logger;
            this.schema                   = schema;
            this.midiClient               = midiClient;
            kitNumber.PreviewTextInput   += TextConversions.CheckDigits;
            userSamples.PreviewTextInput += TextConversions.CheckDigits;
            cancellationTokenSource       = new CancellationTokenSource();

            kitNumber.Text = TextConversions.Format(schema.KitRoots.Count);

            // Capture the input device names, and attempt to guess a reasonable default.
            var allInputDevices      = AudioDevices.GetInputDeviceNames();
            var midiName             = midiClient.OutputName;
            var expectedInputDevices = new[] { $"MASTER ({midiName})", $"IN ({midiName})", $"KICK ({midiName})" };

            inputDevice.ItemsSource   = allInputDevices;
            inputDevice.SelectedIndex = allInputDevices.FindIndex(inputName => expectedInputDevices.Contains(inputName));

            foreach (var group in schema.InstrumentGroups)
            {
                instrumentGroupSelector.Items.Add(group.Description);
            }
        }
Example #6
0
 internal FieldContainer(ModuleSchema schema, string name, string description, ModuleAddress address, string path,
                         int size, IEnumerable <FieldBase> fields)
     : base(schema, name, description, address, path)
 {
     Fields       = fields.ToReadOnlyList(field => field.WithParent(this));
     Size         = size;
     fieldsByName = Lazy.Create(() => Fields.ToDictionary(f => f.Name).AsReadOnly());
 }
Example #7
0
 internal ContainerContainer(ModuleSchema schema, string name, string description, ModuleAddress address, string path, List <IContainer> containers)
     : base(schema, name, description, address, path)
 {
     Containers = containers;
     foreach (ContainerBase container in Containers)
     {
         container.Parent = this;
     }
     ContainersByName = Containers.ToDictionary(c => c.Name).AsReadOnly();
 }
Example #8
0
 internal OverlayDataField(OverlayField field, ModuleSchema schema) : base(field)
 {
     this.schema = schema;
     fieldLists  = SchemaField.FieldLists
                   .ToDictionary(
         pair => pair.Key,
         pair => Lazy.Create(() => new FieldList(pair.Value, schema)))
                   .AsReadOnly();
     // Default to the first overlay, just to make sure we have a valid value right from the start.
     switchIndex = SchemaField.FieldLists.First().Key;
 }
Example #9
0
 internal static bool TryGetKitRoot(string text, ModuleSchema schema, ILogger logger, out VisualTreeNode kitRoot)
 {
     if (!TryParseInt32(text, out var kitNumber) ||
         !schema.KitRoots.TryGetValue(kitNumber, out kitRoot))
     {
         logger?.Log($"Invalid kit number: {text}");
         kitRoot = null;
         return(false);
     }
     return(true);
 }
Example #10
0
 public CopyKitTargetDialog(ModuleSchema schema, ModuleData data, VisualTreeNode sourceKitNode) : this()
 {
     this.schema           = schema;
     this.data             = data;
     sourceKitName.Content = sourceKitNode.KitOnlyDescription.Format(sourceKitNode.Context, data);
     // This is done after other control initialization so that everything is set up.
     // It would probably be more elegant to do everything in a view model and use binding,
     // admittedly.
     kitNumber.TextChanged += HandleKitNumberChanged;
     HandleKitNumberChanged(null, null);
     kitNumber.PreviewTextInput += TextConversions.CheckDigits;
 }
Example #11
0
 internal SoundRecorderDialog(ILogger logger, ModuleSchema schema, RolandMidiClient midiClient)
     : this()
 {
     this.logger                   = logger;
     this.schema                   = schema;
     this.midiClient               = midiClient;
     kitNumber.PreviewTextInput   += TextConversions.CheckDigits;
     userSamples.PreviewTextInput += TextConversions.CheckDigits;
     cancellationTokenSource       = new CancellationTokenSource();
     inputDevice.ItemsSource       = AudioDevices.GetInputDeviceNames();
     kitNumber.Text                = TextConversions.Format(schema.KitRoots.Count);
 }
Example #12
0
 internal static IDataField CreateDataField(IField field, ModuleSchema schema)
 {
     return(field switch
     {
         StringField f => new StringDataField(f),
         BooleanField f => new BooleanDataField(f),
         NumericField f => new NumericDataField(f),
         EnumField f => new EnumDataField(f),
         InstrumentField f => new InstrumentDataField(f, schema),
         OverlayField f => new OverlayDataField(f, schema),
         TempoField f => new TempoDataField(f),
         _ => throw new ArgumentException($"Can't handle {field} yet")
     });
        public InstrumentAudioRecorderViewModel(IViewServices viewServices, ILogger logger, DeviceViewModel deviceViewModel)
        {
            this.logger = logger;
            schema      = deviceViewModel.ConnectedDeviceSchema ?? throw new InvalidOperationException("Cannot record audio without a connected device");
            device      = deviceViewModel.ConnectedDevice ?? throw new InvalidOperationException("Cannot record audio without a connected device");

            Settings = new InstrumentAudioRecorderSettingsViewModel(viewServices, schema, device.InputName);
            Progress = new InstrumentAudioRecorderProgressViewModel();
            Title    = $"Instrument Audio Recorder ({schema.Identifier.Name})";
            StartRecordingCommand     = new DelegateCommand(StartRecording, false);
            CancelCommand             = new DelegateCommand(Cancel, false);
            Settings.PropertyChanged += (sender, args) => UpdateButtonStatus();
        }
Example #14
0
        internal Container ToContainer(ModuleSchema schema, ModuleJson module, string name, int offset, string description, FieldCondition?condition)
        {
            // TODO: This works and is pleasantly efficient, but it's pretty ugly.
            if (cachedFields == null)
            {
                // TODO: Check that all fields are either primitive or container, check the size etc.
                cachedFields = Fields
                               .SelectMany(fieldJson => fieldJson.ToFields(schema, module))
                               .ToList()
                               .AsReadOnly();
            }
            var lastField = Fields.LastOrDefault();
            int size      = Size?.Value ?? lastField?.Offset?.Value ?? 0;
            var common    = new FieldBase.Parameters(schema, name, offset, size, description, condition);

            return(new Container(common, cachedFields));
        }
Example #15
0
        /// <summary>
        /// Reads a kit from a device.
        /// </summary>
        internal static async Task <Kit> ReadKit(ModuleSchema schema, RolandMidiClient client, int kitNumber, IStandardStreamWriter console)
        {
            // Allow up to 30 seconds in total, and 1 second per container.
            var overallToken = new CancellationTokenSource(TimeSpan.FromSeconds(30)).Token;

            var moduleData = new ModuleData();
            var kitRoot    = schema.KitRoots[kitNumber];
            var containers = kitRoot.Context.AnnotateDescendantsAndSelf().Where(c => c.Container.Loadable).ToList();

            console.WriteLine($"Reading {containers.Count} containers from device {schema.Identifier.Name} kit {kitNumber}");
            foreach (var container in containers)
            {
                await PopulateSegment(client, moduleData, container, overallToken, console);
            }
            var clonedData = kitRoot.Context.CloneData(moduleData, schema.KitRoots[1].Context.Address);

            return(new Kit(schema, clonedData, kitNumber));
        }
Example #16
0
 internal DataExplorer(ILogger logger, ModuleSchema schema, ModuleData data, VisualTreeNode rootNode, RolandMidiClient midiClient, string fileName,
                       string saveFileFilter, string explorerName) : this()
 {
     Logger              = logger;
     Schema              = schema;
     Data                = data;
     MidiClient          = midiClient;
     RootNode            = rootNode;
     this.saveFileFilter = saveFileFilter;
     this.explorerName   = explorerName;
     this.fileName       = fileName;
     if (midiClient == null)
     {
         mainPanel.Children.Remove(midiPanel);
     }
     Data.DataChanged += HandleModuleDataChanged;
     LoadView();
     UpdateTitle();
 }
        public InstrumentAudioRecorderSettingsViewModel(IViewServices viewServices, ModuleSchema schema, string midiName)
        {
            this.viewServices = viewServices;
            this.schema       = schema;
            var groups = schema.InstrumentGroups
                         .Where(ig => ig.Preset)
                         .Select(ig => ig.Description)
                         .ToList();

            groups.Insert(0, "(All)");
            InstrumentGroups        = groups;
            selectedInstrumentGroup = groups[0];
            InputDevices            = AudioDevices.GetInputDeviceNames();

            // Try to guess at a reasonable input based on known inputs including the MIDI name.
            var expectedInputDevices = new[] { $"MASTER ({midiName})", $"IN ({midiName})", $"KICK ({midiName})" };

            SelectedInputDevice = InputDevices.FirstOrDefault(inputName => expectedInputDevices.Contains(inputName));

            kitNumber = schema.KitRoots.Count;
            SelectOutputFileCommand = new DelegateCommand(SelectOutputFile, true);
        }
Example #18
0
        public IContainer ToContainer(ModuleSchema schema, ModuleJson module, string name, string description, ModuleAddress address, string?parentPath, SchemaVariables variables)
        {
            string path = PathUtilities.AppendPath(parentPath, name);

            if (Fields is object)
            {
                var fieldList = requiresOverlayResolution ? resolvedFields.Select(FinalizeField) : resolvedFields;
                var realSize  = ModuleOffset.FromDisplayValue(Size.Value).LogicalValue;
                return(new FieldContainer(schema, name, description, address, path, realSize, fieldList));

                FieldBase FinalizeField(FieldBase field) =>
                field is OverlayField overlay?overlay.WithPath(variables.Replace(overlay.SwitchPath)) : field;
            }
            else
            {
                var containers = new List <IContainer>();
                foreach (var container in Containers)
                {
                    containers.AddRange(container.ToContainers(schema, module, address, path, variables));
                }
                return(new ContainerContainer(schema, name, description, address, path, containers));
            }
        }
Example #19
0
 internal FieldContainer(ModuleSchema schema, string name, string description, ModuleAddress address, string path,
                         int size, IReadOnlyList <IField> fields)
     : base(schema, name, description, address, path) =>
     (Size, Fields, FieldsByName) = (size, fields, fields.ToDictionary(f => f.Name).AsReadOnly());
Example #20
0
 public Parameters(ModuleSchema schema, string name, int offset, int size, string description, FieldCondition?condition) =>
 (Schema, Name, Offset, Size, Description, Condition) = (schema, name, offset, size, description, condition);
Example #21
0
        internal IEnumerable <IField> ToFields(ModuleSchema schema, ModuleJson module)
        {
            string         description = ValidateNotNull(Description, nameof(Description));
            string         name        = Name ?? description;
            int?           repeat      = module.GetCount(Repeat);
            var            offset      = ValidateNotNull(Offset, nameof(Offset)).Value;
            FieldCondition?condition   = GetCondition();

            if (repeat == null)
            {
                yield return(ToField(schema, module, name, offset, description, condition));
            }
            else
            {
                var           gap    = ValidateNotNull(Gap, nameof(Gap)).Value;
                List <string>?lookup = null;
                if (DescriptionLookup != null)
                {
                    ValidateNotNull(module.Lookups, nameof(module.Lookups));
                    lookup = module.Lookups.FirstOrDefault(candidate => candidate.Name == DescriptionLookup)?.Values;
                    Validate(lookup != null, "Lookup ${DescriptionLookup} not found for descriptions.");
                    Validate(lookup !.Count == repeat,
                             $"Lookup ${DescriptionLookup} has {lookup.Count} elements; field has repeats {repeat} times.");
                }
                for (int i = 1; i <= repeat; i++)
                {
                    string indexedName     = Invariant($"{name}[{i}]");
                    string indexValue      = i.ToString(CultureInfo.InvariantCulture);
                    string?lookupValue     = lookup?[i - 1];
                    string fullDescription = string.Format(Description, indexValue, lookupValue);
                    yield return(ToField(schema, module, indexedName, offset, fullDescription, condition));

                    offset += gap;
                    // TODO: This is ugly. We need it because otherwise in SetList we end up with offsets of
                    // 0x03_00_00_00
                    // 0x03_00_10_00
                    // 0x03_00_20_00
                    // ....
                    // 0x03_00_70_00
                    // 0x03_00_80_00 => This will be promoted to an *address* of 0x03_01_00_00 automatically...
                    // ...
                    // 0x03_00_f0_00
                    // 0x03_01_00_00 => We now get 0x03_01_00_00 again :(
                    // 0x03_01_10_00
                    // But it's annoying to have this *here*...

                    if ((offset & 0x80) != 0)
                    {
                        offset += 0x80;
                    }
                    if ((offset & 0x80_00) != 0)
                    {
                        offset += 0x80_00;
                    }
                    if ((offset & 0x80_00_00) != 0)
                    {
                        offset += 0x80_00_00;
                    }
                }
            }

            FieldCondition?GetCondition()
            {
                if (Condition is null)
                {
                    return(null);
                }
                int conditionOffset = ValidateNotNull(Condition.Offset, nameof(Condition.Offset)).Value;
                int requiredValue   = ValidateNotNull(Condition.RequiredValue, nameof(Condition.RequiredValue));

                return(new FieldCondition(conditionOffset, requiredValue));
            }
        }
Example #22
0
 /// <summary>
 /// Creates a new instance.
 /// </summary>
 /// <param name="schema">The schema of the module whose audio was sampled.</param>
 /// <param name="format">The format of all the samples.</param>
 /// <param name="durationPerInstrument">The length of each sample.</param>
 /// <param name="captures">The captured audio data.</param>
 public ModuleAudio(ModuleSchema schema, AudioFormat format, TimeSpan durationPerInstrument, IReadOnlyList <InstrumentAudio> captures) =>
 (Schema, Format, DurationPerInstrument, Captures) = (schema, format, durationPerInstrument, captures);
Example #23
0
 public ModuleSchema LoadTD27Schema() =>
 ModuleSchema.FromAssemblyResources(typeof(ModuleSchema).Assembly, "TD27", "TD27.json");
Example #24
0
 internal InstrumentDataField(InstrumentField field, ModuleSchema schema) : base(field)
 {
     // TODO: Use primitive data fields as we do in TempoDataField?
     Schema = schema;
 }
Example #25
0
 private protected ContainerBase(ModuleSchema schema, string name, string description, ModuleAddress address, string path) =>
 (Schema, Name, Description, Address, Path) = (schema, name, description, address, path);
Example #26
0
 internal ContainerContainer BuildPhysicalRoot(ModuleSchema schema) =>
 (ContainerContainer)Containers !["Root"].ToContainer(