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);
            }
        }
Exemple #2
0
        internal InstrumentAudioExplorer(ILogger logger, ModuleAudio audio, string fileName) : this()
        {
            this.audio      = audio;
            this.logger     = logger;
            Title           = $"{Title} - {fileName}";
            capturesByGroup = audio.Captures.ToLookup(c => c.Instrument.Group);
            var allOutputDeviceNames = AudioDevices.GetOutputDeviceNames();

            outputDevice.ItemsSource = allOutputDeviceNames;

            // Assume that device 0 is the default. That will usually be the case.
            if (allOutputDeviceNames.Count > 0)
            {
                outputDevice.SelectedIndex = 0;
            }

            moduleId.Content    = audio.Schema.Identifier.Name;
            userSamples.Content = TextConversions.Format(capturesByGroup[null].Count());
            var format = audio.Format;

            audioFormat.Content       = $"Channels: {format.Channels}; Bits: {format.Bits}; Frequency: {format.Frequency}";
            timePerInstrument.Content = TextConversions.Format(audio.DurationPerInstrument.TotalSeconds);

            var groups = capturesByGroup.Select(c => new InstrumentGroupOrUserSample(c.Key)).Distinct();

            treeView.ItemsSource           = groups;
            instrumentsGroupBox.Visibility = Visibility.Collapsed;
        }
Exemple #3
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);
 }
        private Config TryCreateConfig()
        {
            if (inputDevice.SelectedIndex == -1)
            {
                return(null);
            }
            string deviceName = (string)inputDevice.Items[inputDevice.SelectedIndex];
            int?   deviceId   = AudioDevices.GetAudioInputDeviceId(deviceName);

            if (deviceId == null)
            {
                return(null);
            }
            int midiChannel = int.Parse(midiChannelSelector.Text);

            if (!TextConversions.TryParseDecimal(recordingTime.Text, out var recordingSeconds))
            {
                return(null);
            }
            TimeSpan recordingDuration = TimeSpan.FromSeconds((double)recordingSeconds);

            if (!TextConversions.TryGetKitRoot(kitNumber.Text, schema, logger, out var kit))
            {
                return(null);
            }
            if (outputFile == null)
            {
                return(null);
            }
            if (!TextConversions.TryParseInt32(userSamples.Text, out int parsedUserSamples))
            {
                return(null);
            }
            if (parsedUserSamples < 0 || parsedUserSamples > schema.UserSampleInstruments.Count)
            {
                return(null);
            }

            return(new Config
            {
                KitRoot = kit,
                RecordingDuration = recordingDuration,
                OutputFile = outputFile,
                AudioDeviceId = deviceId.Value,
                InstrumentGroup = instrumentGroupSelector.SelectedIndex - 1,
                UserSamples = parsedUserSamples,
                MidiChannel = midiChannel,
                Attack = (int)attackSlider.Value,
            });
        }
Exemple #5
0
 private async void PlaySample(object sender, RoutedEventArgs args)
 {
     try
     {
         InstrumentAudio capture  = (InstrumentAudio)((Button)sender).Tag;
         int?            deviceId = AudioDevices.GetAudioOutputDeviceId(outputDevice.Text);
         if (deviceId == null)
         {
             return;
         }
         // TODO: Allow audio playback cancellation. Seems unlikely we'll actually need it.
         await AudioDevices.PlayAudio(deviceId.Value, audio.Format, capture.Audio, CancellationToken.None);
     }
     catch (Exception e)
     {
         logger.Log("Error playing sample", e);
     }
 }
Exemple #6
0
        internal InstrumentAudioExplorer(ILogger logger, ModuleAudio audio) : this()
        {
            this.audio               = audio;
            this.logger              = logger;
            capturesByGroup          = audio.Captures.ToLookup(c => c.Instrument.Group);
            outputDevice.ItemsSource = AudioDevices.GetOutputDeviceNames();

            moduleId.Content    = audio.Schema.Identifier.Name;
            userSamples.Content = TextConversions.Format(capturesByGroup[null].Count());
            var format = audio.Format;

            audioFormat.Content       = $"Channels: {format.Channels}; Bits: {format.Bits}; Frequency: {format.Frequency}";
            timePerInstrument.Content = TextConversions.Format(audio.DurationPerInstrument.TotalSeconds);

            var groups = capturesByGroup.Select(c => new InstrumentGroupOrUserSample(c.Key)).Distinct();

            treeView.ItemsSource           = groups;
            instrumentsGroupBox.Visibility = Visibility.Collapsed;
        }
        private async void StartRecording(object sender, RoutedEventArgs args)
        {
            var config = TryCreateConfig();

            // Shouldn't really happen, as the button shouldn't be enabled.
            if (config == null)
            {
                return;
            }

            // Load all the details
            var instrumentRoot = config.KitRoot.DescendantNodesAndSelf().FirstOrDefault(node => node.InstrumentNumber == 1);

            if (instrumentRoot == null)
            {
                logger.LogError($"No instrument root available. Please email a bug report to [email protected]");
                return;
            }

            var data          = new ModuleData();
            var midiNoteChain = instrumentRoot.MidiNoteField;

            if (midiNoteChain == null)
            {
                logger.LogError($"No midi field available. Please email a bug report to [email protected]");
                return;
            }

            logger.LogInformation($"Starting recording process");
            var midiNoteContext = midiNoteChain.GetFinalContext(instrumentRoot.Context);

            logger.LogInformation($"Loading existing data to restore after recording");
            List <FixedContainer> instrumentContainers;

            try
            {
                await LoadContainerAsync(data, midiNoteContext);

                instrumentContainers = instrumentRoot.DescendantNodesAndSelf()
                                       .SelectMany(node => node.Details)
                                       .Select(detail => detail.Container)
                                       .Where(fc => fc != null)
                                       .Distinct()
                                       .ToList();
                foreach (var container in instrumentContainers)
                {
                    await LoadContainerAsync(data, container);
                }
            }
            catch (Exception e)
            {
                logger.LogError($"Error loading data for recording", e);
                return;
            }

            data.Snapshot();

            var(instrumentFieldContext, instrumentField) =
                (from ct in instrumentContainers
                 orderby ct.Address
                 from field in ct.Container.Fields
                 where field is InstrumentField
                 select(ct, (InstrumentField)field)).FirstOrDefault();
            if (instrumentFieldContext == null)
            {
                logger.LogError($"No instrument field available. Please email a bug report to [email protected]");
                return;
            }

            var midiNote = midiNoteChain.FinalField.GetMidiNote(midiNoteContext, data);

            if (midiNote == null)
            {
                logger.LogError($"No midi note for instrument 1. Please email a bug report to [email protected]");
            }

            var presetInstrumentsToRecord = schema.PresetInstruments
                                            .Where(ins => config.InstrumentGroup == -1 || ins.Group.Index == config.InstrumentGroup)
                                            .ToList();

            progress.Maximum = presetInstrumentsToRecord.Count + config.UserSamples;

            logger.LogInformation($"Starting recording process");
            try
            {
                var captures = new List <InstrumentAudio>();
                progress.Value = 0;
                foreach (var instrument in presetInstrumentsToRecord)
                {
                    var instrumentAudio = await RecordInstrument(instrument);

                    captures.Add(instrumentAudio);
                }
                for (int i = 0; i < config.UserSamples; i++)
                {
                    var instrumentAudio = await RecordInstrument(schema.UserSampleInstruments[i]);

                    captures.Add(instrumentAudio);
                }
                var moduleAudio = new ModuleAudio(schema, AudioDevices.AudioFormat, config.RecordingDuration, captures.AsReadOnly());
                using (var output = File.Create(config.OutputFile))
                {
                    moduleAudio.Save(output);
                }
                logger.LogInformation($"Saved instrument sounds to {config.OutputFile}.");
            }
            catch (OperationCanceledException)
            {
                logger.LogWarning("Cancelled recording");
            }
            catch (Exception e)
            {
                logger.LogError($"Error recording data", e);
            }
            finally
            {
                data.RevertSnapshot();
                await RestoreData(data);
            }
            Close();

            async Task <InstrumentAudio> RecordInstrument(Instrument instrument)
            {
                progress.Value++;
                progressLabel.Content = $"Recording {instrument.Name}";
                foreach (var container in instrumentContainers)
                {
                    container.Container.Reset(container, data);
                }
                // Note: setting the instrument resets VEdit data to defaults
                instrumentField.SetInstrument(instrumentFieldContext, data, instrument);
                foreach (var container in instrumentContainers)
                {
                    var segment = data.GetSegment(container.Address);
                    midiClient.SendData(segment.Start.Value, segment.CopyData());
                    await Task.Delay(40, CancellationToken);
                }
                midiClient.Silence(config.MidiChannel);
                await Task.Delay(40);

                var recordingTask = AudioDevices.RecordAudio(config.AudioDeviceId, config.RecordingDuration, CancellationToken);

                midiClient.PlayNote(config.MidiChannel, midiNote.Value, config.Attack);
                var audio = await recordingTask;

                return(new InstrumentAudio(instrument, audio));
            }
        }