giada icon indicating copy to clipboard operation
giada copied to clipboard

Multi-channel Routing + Record Modes

Open hugoaboud opened this issue 6 years ago • 24 comments

I've forked giada and have been working on it on the last few days. My fork is still unstable because I've changed some structural stuff (described below), but I'm working on it.

Multi-channel Routing Audio/MIDI goes into InputChannels, is processed, routed to ColumnChannels where it serves as input to SampleChannels and MIDIChannels that output back to their parent ColumnChannel where it's processed again and finally outputted.

image

I've introduced the following class hierarchy with the existing core elements:

  • Channel: mostly virtual, handles actions, input, FX processing and output;
  • ResourceChannel: mostly virtual, handles playback and recording;
  • InputChannel: de-interleaves soundcard input on selected index and routes to selected ColumnChannel;
  • ColumnChannel: takes inputs from n InputChannels, routes to children ResourceChannels and their output to soundcard output;

image

Some interesting points about the multi-channel implementation are:

  • Input monitoring is handled by channel and it's possible to activate it individually for any Input, Column, Sample and MIDI channels, to fit any user needs.
  • Audio buffering for every channel is deactivated if the chain doesn't need it (not recording or monitoring).
  • Channels now have a pre-mute, that mutes before the FX (so you can have tails on reverb/delay like effects). Sample/MIDI channels don't have it on UI, gotta work on that.

All the inputs and outputs are currently Mono only. Some features aren't implemented yet (such as renaming), those are listed here: https://github.com/hugoaboud/giada/issues/1

Record Modes

I've also improved the recording behavior: If Input Rec is kept on, the record button on ResourceChannels acts immediately instead of arming the channel. This allows independent recording on different channels. When Input Rec goes off it triggers all recordings to stop.

Now I'm working on Record Modes: matching the recording behavior to the channel Loop Mode, so that you're able to control whether recording should sync to sequencer (loop) or not (oneshot), overdub on end (repeat) or not (single), etc.

Also I need to fix a few things that were broken on this refactoring (like copy, move and patch methods), but a few more weeks should do it. If you'd like to clone my fork and test it, find where it cracks, that'd be really good. And congratulations on the great software, I'm having a great time with it.

hugoaboud avatar Mar 17 '18 04:03 hugoaboud

Thank heavens. This is what I've been looking for.

Would be neat if you'd realize the record nodes.

Thanks.

vale981 avatar Mar 23 '18 09:03 vale981

@hugoaboud I took some time to play with your fork. Even if in an early stage, I really appreciated (feature-wise) the idea of dynamic input channels and how columns are used for I/O grouping, instead of being simple interface elements as they are right now.

For some obscure reason I was able to start input recording only once. Now I can't seem to re-enable the input device after tweaking it in the configuration window. But I guess this is one of those things you are going to fix in the next development cycle.

Anyway I will keep an eye on your work so at some point in the future we might include part of those features into the main branch. If you agree of course ;)

monocasual avatar Mar 25 '18 10:03 monocasual

I may remark, that record modes are a very crucial point. I am missing a luppp like "record till bar finishes" behavior.

Cheers.

PS: I am currently engaged in another project, but I am glad to help here and will look into the record mode thing to see if I can hack something together.

On 25 March 2018 12:42:05 CEST, Monocasual Laboratories [email protected] wrote:

@hugoaboud I took some time to play with your fork. Even if in an early stage, I really appreciated (feature-wise) the idea of dynamic input channels and how columns are used for I/O grouping, instead of being simple interface elements as they are right now.

For some obscure reason I was able to start input recording only once. Now I can't seem to re-enable the input device after tweaking it in the configuration window. But I guess this is one of those things you are going to fix in the next development cycle.

Anyway I will keep an eye on your work so at some point in the future we might include part of those features into the main branch. If you agree of course ;)

-- You are receiving this because you commented. Reply to this email directly or view it on GitHub: https://github.com/monocasual/giada/issues/175#issuecomment-375960793

-- Sent from my Android device with K-9 Mail. Please excuse my brevity.

vale981 avatar Mar 25 '18 11:03 vale981

Thanks @vale981 and @monocasual, if you find any other issue please list it here or on the roadmap of my fork, I'm keeping track of known issues there. I had to take a few days away from it and focus on my job, but I can't take too long to finish it, so this week I'm going for another sprint.

I'm really developing this for the community, hoping from the start that it could be merged into the main branch and maybe help other people with their music. When the time comes I'll be glad to help on the merge.

Cheers!

hugoaboud avatar Mar 26 '18 00:03 hugoaboud

@monocasual what's the best way to tell a dialog it should refresh from the main window and vice versa? Most of my issues now relate to UI not updating when needed. For example: if I delete/rename a column on the main window it should also be deleted from the ColumnList dialog. I'm starting the Opaque Channels merge today so I can properly implement Record Modes.

hugoaboud avatar Apr 06 '18 15:04 hugoaboud

@hugoaboud I think the best way to do that is to add a new controller (src/glue) that takes care of updating or rebuilding the two widget containers when something happens. This is how we handle any communication between model and multiple sub-views.

monocasual avatar Apr 12 '18 20:04 monocasual

@monocasual I've created/edited a few methods on glue/channel.cpp using gu_getSubwindow to get the open dialog (if any) and update it. Works like a charm! My last commit has rename/remove fully implemented for Input and Column channels, I've already merged opaque channels. Now I'm starting to implement Record Modes (button and attribute on ResourceChannel are already there) and fixing playback. Also the configuration issue you've reported is gone.

I've added to my roadmap the channel mono/stereo feature, should work on it soon so input routing gets more flexible.

hugoaboud avatar Apr 13 '18 01:04 hugoaboud

I've noticed the oneshot quantization on your current version seems to be wrong for 2b, 4b, etc.. It seems to be dividing the trigger time instead of multiplying it. I expected 2b to quantize for 2 beats instead of 0.5, i'm digging in to change it, is that a known issue?

EDIT: I've modified src/clock.cpp: void updateQuanto() { if (quantize != 0) quanto = framesInBeat / quantize; } to void updateQuanto() { if (quantize != 0) quanto = framesInBeat * quantize; } Working fine now, I just need to change the status to WAIT for user feedback and enable canceling.

hugoaboud avatar Apr 13 '18 02:04 hugoaboud

@hugoaboud , actually the code is correct, the quantizer set to 2b means "1/2 beat", i.e. 2 events allowed per beat. I think the current terminology "2b", "4b", ... is misleading, we should change it to 1/2, 1/4, ... and so on.

monocasual avatar Apr 15 '18 15:04 monocasual

@monocasual ok, but i feel like I could need quantize to 2 ou 4 beats, what do you say I add those options and change the terminology, so the user can choose "4b", "2b", "1b", "1/2b", "1/4b" etc?

hugoaboud avatar Apr 15 '18 16:04 hugoaboud

@vale981 I've pushed a commit with the basics of Record Modes working. Would you help me test and find where it crashes?

When channel recording starts it creates a wave with arranger size. The user is able to change the arranger size while recording. The channel's wave and recording will stay bound to the initial size.

  • Single: record a single layer
  • Overdub: record layers until user stop. while overdubbing the previous wave content is outputted
  • Zero: start/stop on arranger zero
  • Quantize: start/stop on quantize
  • Play: play on finish recording

giada_recmode

I've also started the mono/stereo integration. The input channels selection on tabAudio now relates to the number of channels to read from the soundcard. InputChannels may be toggled between mono and stereo, and the mono<>stereo conversion when routing audio is done. I'm currently assuming ColumnChannels and SampleChannels are always stereo. Changing them to mono will probably crash (there's no UI way to do it). This should be improved on the next sprint. Output remains fixed to the stereo channel selected on tabAudio.

I'm close to what I need, now it's time to hunt bugs/crashes and fix things like patch and copy. It's been a good time!

PS: MIDI Channel is currently broken

hugoaboud avatar Apr 15 '18 19:04 hugoaboud

Hi. I am sorry for not responding. I've been bussy lately, but very happy to test this over the weekend. Thanks!

vale981 avatar Jun 01 '18 10:06 vale981

I've tested my build today with a Focusrite Scarlett 18i20, all the inputs and outputs are showing up and the multi-track routing seems to work fine. Mono/stereo and record modes are also working so far.

I'm having some problem with the buffer size when using Alsa, giada doesn't seem to be able to set the soundcard buffersize, so when I select a wrong value it ring shifts. The same happens when another application tries to use the soundcard. I've been able to record columns simultaneously with different inputs.

Now I've got to review plugins and the serialization of the new channel classes.

hugoaboud avatar Jun 07 '18 05:06 hugoaboud

Hi @monocasual, it's been a while but I'm almost done with the features. Basically I need to fix the MIDI channel, patch seralization and some other minor issues/features. Would you mind taking a look at my fork?

It slightly changes the way recording and audio routing works, to support multiple inputs recording to multiple channels simultaneously. Also the new Channel class structure might conflict with older patches so I might need to write a little patch converting tool. When you test it, be sure to set the input on the ColumnChannel (either on the subWindow or the keyboard column button). All the already implemented features are listed here: https://github.com/hugoaboud/giada/issues/2

What do you think? I'd really like to merge it with the main branch.

hugoaboud avatar Jul 03 '18 07:07 hugoaboud

hey @hugoaboud , sorry for the delay. We were pretty busy with the massive audioBuffer refactoring (v0.15.1, will be released in a couple of days). I will surely take a ride on your fork, as soon as the new version has been packaged and shipped. Thanks for your time (and patience)

monocasual avatar Jul 03 '18 13:07 monocasual

@monocasual nice! I've found some new crashes today, but I should be able to fix them soon.

As I'm working on MIDI Channels now some pre-implementation questions popped up. If you could clarify it to me it'd be really helpful.

  • Why doesn't MIDI Channels has the Status Button?
  • Also, why doesn't it has Loop Modes?
  • Do Record Actions only enable recording on MIDIChannels or does it enable automation recording on every channel (keyPress actions etc)? I couldn't record the automation, but I'd just like to be sure.

InputChannels allow the user to select both a midi and an audio input for the same input channel (for plugins like vocoder, or for using sample and midi channels on the same column). That means if you put a VSTi on the InputChannel plugin stack it can be recorded to a SampleChannel. (Looping audio instead of midi saves plugin processing time). But the user might also be able to record the midi directly into the channel. And in that case I believe status, loops modes and record modes should be available for MIDI as well. That means generalizing the whole playback/recording behaviour (loop modes, status, begin, end, position, etc.) to ResourceChannel. Processing and storing are handled by the sample or midi channel.

What are your thoughts on that? Sorry for the long explanation.

UPDATE:

I haven't found any tutorial on Action Recording, and couldn't record to a midi track on the latest giada version, is it implemented yet? What am I missing? I also need to be able to select between multiple devices(ports), so this is something I should implement too. I'm thinking of a device list (with add and remove options) under the buttons where you select a device to change it's Input, Output and Name. Then for each InputChannel you select a device from the list. Sounds good?

hugoaboud avatar Jul 03 '18 19:07 hugoaboud

screen3 I'm not exactly the UI guy, so I think this should be improved, but i've pushed a commit with the multiple MIDI device working. Each MidiDevice creates a RtMidiIn/RtMidiOut instance and opens a Port on it. The midi dispatcher receives the callback with a pointer to the MidiDevice. When dispatching to the input channels it calls receiveMidi on the channels with a selected MIDI input, and from each input channel call Columns receiveMidi and Resources receiveMidi. You must turn the InputChannel's input monitoring on to hear the VSTi as you play.

PS: there's a known crash on deleting channels, should fix it soon.

hugoaboud avatar Jul 05 '18 12:07 hugoaboud

@hugoaboud MIDI channels differ from Sample channels in how they are handled by the Audio Engine. Sample channels are chunks of audio data (with loop modes and such), while MIDI channels are basically actions (i.e. events) and they are tightly bound to the sequencer. If the sequencer isn't running, a MIDI channel can't be played - the audio engine wouldn't know which event to trigger. That's why MIDI channels don't have the status button, nor the loop mode: they act like MIDI events containers as in any other DAW out there. The events are triggered by the sequencer itself.

For the direct recording MIDI -> audio: sounds good. I'm not sure how to handle multiple FX stacks though, e.g. synth + delay + reverb...

EDIT: MIDI recording should be there :) can this be of any help? https://giadamusic.com/documentation-recording-actions

monocasual avatar Jul 05 '18 17:07 monocasual

@monocasual I see it. I won't use MIDI Channels on my set, but in a sense sample channels in loop mode are also bound to the sequencer. If the MIDIChannel could keep a playback tracker just like SampleChannel I think adding status and loop modes would add up to the functionalities (having oneshot midi channels for example). But as I won't need it (recording audio from input channels is fine) I should just roll back the modifications I've started and get it working as the original.

What do you mean by handling multiple FX stacks?

Sorry I haven't paid attention to this section of the documentation. I'll keep working on the small issues today. The MIDI Devices list should be saved within the patch or config?

Thanks for the attention! Sorry for so many questions.

hugoaboud avatar Jul 05 '18 19:07 hugoaboud

@hugoaboud

What do you mean by handling multiple FX stacks?

I mean: say you have a Synth + a delay + a Reverb: is your solution able to record the full output of such vst chain (and not only the Synth output)?

The MIDI Devices list should be saved within the patch or config?

This is global information so it should be stored in the configuration file

monocasual avatar Jul 14 '18 16:07 monocasual

Here's a kind of UI/UX I'd love to see:

giada

rnkn avatar Jun 20 '19 13:06 rnkn

Is it possible for a retrospective recording to be implemented?

gamerey45 avatar Aug 07 '19 23:08 gamerey45

Is it possible for a retrospective recording to be implemented?

Retrospective recording is a cool yet advanced DAW feature, a bit outside the scope of a minimalistic loop machine such as Giada.

monocasual avatar Aug 08 '19 08:08 monocasual

@hugoaboud any updates on this?

gvnnz avatar Jul 23 '21 14:07 gvnnz