Skip to content

Commit

Permalink
one-shot samples: Introduce recording of the one-shot samples
Browse files Browse the repository at this point in the history
- Implemented 'one-shot' mode for voice synth
- Fixed bugs related to typos during the adaptation to the change of
the coding style
- Fixed issue with non-stored MIDI mappings
- Updated the README.md
- Fixed typo in traces

Signed-off-by: Vladyslav Goncharuk <svlad1990@gmail.com>
  • Loading branch information
svlad-90 committed Nov 12, 2023
1 parent 68eebbe commit 92820e9
Show file tree
Hide file tree
Showing 22 changed files with 301 additions and 71 deletions.
2 changes: 1 addition & 1 deletion input_controller/fx_preset.py
Original file line number Diff line number Diff line change
Expand Up @@ -212,7 +212,7 @@ def __load_midi_mappings_from_persistency(self):

def __store_midi_mappings_to_persistency(self):
midi_mappings = self.get_midi_mappings_as_lists()
print(f"storing {str(len(midi_mappings))} midi mappings from persistency - {midi_mappings}")
print(f"storing {str(len(midi_mappings))} midi mappings to persistency - {midi_mappings}")
self.__persistency_item.set_midi_mapping(midi_mappings)

def __load_data(self):
Expand Down
9 changes: 8 additions & 1 deletion input_controller/fx_preset_page.py
Original file line number Diff line number Diff line change
Expand Up @@ -116,4 +116,11 @@ def set_active_fx_unit(self, active_fx_unit):
self.__fx_presets[self.__selected_fx_preset_id].view_update_active_fx_unit()

def get_active_fx_unit(self):
return self.__fx_presets[self.__selected_fx_preset_id].get_active_fx_unit()
return self.__fx_presets[self.__selected_fx_preset_id].get_active_fx_unit()

def get_active_fx_unit_custom(self, fx_preset_id):
return self.__fx_presets[fx_preset_id].get_active_fx_unit()

def set_active_fx_unit_custom(self, fx_preset_id, active_fx_unit):
self.__fx_presets[fx_preset_id].set_active_fx_unit(active_fx_unit)
self.__fx_presets[fx_preset_id].view_update_active_fx_unit()
12 changes: 8 additions & 4 deletions input_controller/korg_kaoss_pad_3_plus_input_controller.py
Original file line number Diff line number Diff line change
Expand Up @@ -182,9 +182,13 @@ def select_fx_preset_on_the_visible_page(self, preset_fx_id):
def update_fx_preset(self, fx_preset_id):
print(self.__context.device_name + ': ' + KorgKaossPad3PlusInputController.update_fx_preset.__name__)

if self.is_save_mode() and self.__save_from_preset_page_id and self.__save_from_preset_id:
if self.is_save_mode() and self.__save_from_preset_page_id != None and self.__save_from_preset_id != None:
self.__fx_preset_pages[self.__selected_fx_preset_page]\
.set_midi_mappings(fx_preset_id, self.__fx_preset_pages[self.__save_from_preset_page_id].get_midi_mappings(self.__save_from_preset_id))
.set_midi_mappings(fx_preset_id, self.__fx_preset_pages[self.__save_from_preset_page_id]\
.get_midi_mappings(self.__save_from_preset_id))
self.__fx_preset_pages[self.__selected_fx_preset_page]\
.set_active_fx_unit_custom(fx_preset_id, self.__fx_preset_pages[self.__save_from_preset_page_id]\
.get_active_fx_unit_custom(self.__save_from_preset_id))

self.__fx_preset_pages[self.__selected_fx_preset_page].update_fx_preset(fx_preset_id)

Expand Down Expand Up @@ -371,7 +375,7 @@ def on_midi_msg(self, event):
self.set_shift_pressed_state(event.data2 == fl_helper.MIDI_MAX_VALUE)
else:
if self.__midi_mapping_input_dialog:
self.__midi_mapping.InputDialog.on_midi_msg(event)
self.__midi_mapping_input_dialog.on_midi_msg(event)
else:
if event.data1 == constants.MIDI_CC_EFFECTS_PAGE_1 and self.get_shift_pressed_state():
self.select_fx_page(FxPresetPage.fx_preset_page_1)
Expand Down Expand Up @@ -456,7 +460,7 @@ def on_midi_msg(self, event):
self.set_save_mode(False)
self.select_fx_preset_on_the_visible_page(FxPreset.fx_preset_7)
elif event.data1 == constants.MIDI_CC_EFFECT_8 and self.is_save_mode():
self.update_fx_preset(FxPreset.fx_preset_8, self.__fx_preset_pages[self.__selected_fx_preset_page])
self.update_fx_preset(FxPreset.fx_preset_8)
self.set_save_mode(False)
self.select_fx_preset_on_the_visible_page(FxPreset.fx_preset_8)
elif event.data1 == constants.MIDI_CC_EFFECT_1 and not self.get_shift_pressed_state():
Expand Down
4 changes: 2 additions & 2 deletions input_controller/midi_mapping_input_dialog.py
Original file line number Diff line number Diff line change
Expand Up @@ -102,7 +102,7 @@ def on_midi_msg(self, event):
self.__midi_mapping_input_client.midi_mapping_input_cancelled()
elif event.data1 == MIDI_CC_6 and self.__midi_mapping_input_client.get_shift_pressed_state():
print(MSG_PREFIX + " >>> Mapping was deleted.")
self.__midi_mapping_input_client.midi_mapping_input_done(self.__selected_fx_parameter_number, midi_mapping())
self.__midi_mapping_input_client.midi_mapping_input_done(self.__selected_fx_parameter_number, MidiMapping())
elif self.__state == MidiMappingInputDialog.STATE_SELECT_PLUGIN_PARAMETER_ID:
if event.data1 == MIDI_CC_NEXT_ITEM and event.data2 == constants.KP3_PLUS_ABCD_PRESSED:
param_count = plugins.getParamCount(self.__plugins_mixer_channel, self.__selected_plugin_number, True)
Expand All @@ -125,7 +125,7 @@ def on_midi_msg(self, event):
elif event.data1 == MIDI_CC_SELECT and event.data2 == constants.KP3_PLUS_ABCD_PRESSED:
parameter_name = plugins.getParamName(self.__selected_parameter_id, self.__plugins_mixer_channel, self.__selected_plugin_number, True)
print(MSG_PREFIX + " >>> Parameter #" + str(self.__selected_parameter_id) + f" '{parameter_name}' was selected")
midi_mapping = midi_mapping(self.__selected_plugin_number,
midi_mapping = MidiMapping(self.__selected_plugin_number,
self.__selected_parameter_id)
self.__midi_mapping_input_client.midi_mapping_input_done(self.__selected_fx_parameter_number, midi_mapping)
self.__state = MidiMappingInputDialog.STATE_FINAL
Expand Down
Binary file modified live_looping.flp
Binary file not shown.
Binary file modified md/input-controller/resources/logical-devices-schema.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
6 changes: 4 additions & 2 deletions md/prerequisites/prerequisites.md
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,8 @@ The project is building the logical devices on the top of the FL Studio DAW and
- **Crossfade Loop Synth by Expert Sleepers** - https://www.expert-sleepers.co.uk/xfadelooper.html
![Augustus loop VST plugin](./vst-plugins/crossfade_loop_synth.jpg)
- **VFX Midi Strip** - [This one is free. Can be downloaded here.](../../VFX%20Midi%20Strip_x64.dll)
![InstantSampler](./vst-plugins/instant_sampler.jpg)
- **InstantSampler** - [This one is free. Can be downloaded here.](https://plugins4free.com/plugin/915/)

Buy, download and install the above set of VST plugins.

Expand Down Expand Up @@ -113,9 +115,9 @@ But all the above ones are part of the FL Studio delivery. So no additional worr

![Novation Bass Station 2](./hardware/novation-bass-station-2.jpg)

You will need one, if you want to use the crossfade loop synth VST. It allows you to grab input from the microphone and instantly loop it. Then you can play your own voice on keyboard.
You will need one, if you want to use the crossfade loop synth VST. It allows you to grab input from the microphone and instantly loop it. Then, you can play your voice on the keyboard.

I'm using Novation Bass Station 2 just as a MIDI keyboard to control an instance of the crossfade loop synth VST plugin. So, once again, feel free to replace it wit any suitable MIDI keyboard. But keep in mind, that you'll need to adjust the MIDI mappings and logic in the 'device_novation_bass_station_2_voice_synth' FL MIDI scripting device.
I'm using Novation Bass Station 2 just as a MIDI keyboard to control an instance of the crossfade loop synth VST plugin. So, once again, feel free to replace it with any suitable MIDI keyboard. But keep in mind, that you'll need to adjust the MIDI mappings and logic in the 'device_novation_bass_station_2_voice_synth' FL MIDI scripting device.

----

Expand Down
Binary file added md/prerequisites/vst-plugins/instant_sampler.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added md/voice-synth/resources/adsr.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added md/voice-synth/resources/hard-sync.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added md/voice-synth/resources/record-feedback.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added md/voice-synth/resources/saturation-params.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added md/voice-synth/resources/volume.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
152 changes: 150 additions & 2 deletions md/voice-synth/voice-synth.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,161 @@
# Table of contents

- ["Voice synth" logical device](#voice-synth-logical-device)
* [Overview](#overview)
* [Crossfade loop](#crossfade-loop)
* [Recording the crossfade loop](#recording-the-crossfade-loop)
* [Attack, decay, sustain, release](#attack-decay-sustain-release)
* [Saturation](#saturation)
* [Loop start and end points](#loop-start-and-end-points)
* [Hard sync](#hard-sync)
* [Record feedback](#record-feedback)
* [Volume](#volume)
* [One shot samples](#one-shot-samples)
* [Recording one-shot samples](#recording-one-shot-samples)

----

# "Voice synth" logical device

## Overview
The "voice synth" logical device is an entity that allows you to capture your own voice from the microphone and:

- create a crossfade loop out of your voice so that you can use the timbre of your voice to play it on the MIDI keyboard
- record one-shot samples from the microphone input, assign them to specific keys on the MIDI keyboard, and then trigger those samples using the keyboard

In all the above use cases the microphone input is captured after the 'input controller' effects.

The following schema shows the main idea of this logical device:

![Logical devices schema](./resources/logical-devices-schema.jpg)

**Note!** This logical device does not have GUI in the FL Studio.

----

## Crossfade loop

### Recording the crossfade loop

Initially, the device has no input data. So the attempt to use the keyboard will lead to silence.

Use the 'Oscillators -> Sub Oscillator Octave' switch to record the crossfade loop and record some data:

![Recording crossfade loop](./resources/recording-cross-fade-loop.jpg)

- Position 1 - recording
- Position 2 - not recording

The recorded loop size is around 1 second. Recording overwrites itself. The expected workflow is the following:

- Put switch to position 1
- Simultaneously with that start to use your voice to apply the timbre. Use some beatbox sounds, e.g. siren or lip roll
- Put switch to position 2 right after recording is over
- Use the keyboard to play the sounds

**Note!** This switch works only if you are not in the 'one-shot samples' state.

**Note!** All adjustable 'crossfade loop' parameters are reset after entering 'record' mode.

----

### Attack, decay, sustain, release

When you're operating in the 'crossfade loop' mode, you can use the synth's ADSR faders in the 'Envelopes' section to change the shape of the sound:

![ADSR](./resources/adsr.jpg)

----

### Saturation

When you're operating in the 'crossfade loop' mode, you can use the following synth's knobs to change the saturation of the sound:

![Saturation](./resources/saturation-params.jpg)

The 'Effects -> Distortion' knob adjusts the saturation amount. And the 'Effects -> Osc Filter Mod' knob adjusts the saturation shape.

----

### Loop start and end points

When you're operating in the 'crossfade loop' mode, you can use the following synth's knobs to change the crossfade loop's start and end points:

![Loop start and end points](./resources/loop-start-and-end-points.jpg)

- 'Mixer -> Osc 1' moves the 'start point' cursor
- 'Mixer -> Osc 2' moves the 'end point' cursor

The above parameters can select a sub-sample from the recorded piece. In some cases, it allows you to make your sound more consistent. In others - to produce some weird sound-effects. Anyway, it is a useful feature, as it helps to find the suitable timbre in real-time during the performance.

----

### Hard sync

When you're operating in the 'crossfade loop' mode, you can use the following synth's knobs to change the crossfade loop's hard sync parameters:

![Hard sync](./resources/hard-sync.jpg)

- 'Filters -> Mod Env Depth' adjusts the 'hard sync cycle' parameter
- 'Filters -> LFO 2 depth' adjusts the 'hard sync detune' parameter

‘Hard Sync’ borrows another concept from classic analog synths - that of oscillator sync.

In traditional synthesis, the frequency of one oscillator is forced onto the waveform of another. In Crossfade Loop Synth, this is done by adjusting the loop length so that the loop repeats at the desired audio frequency. The result is more like synthesis than sample playback - but synthesis with a waveform from the sample buffer. In effect, a kind of wavetable synthesis. By moving the loop point through your sample, you can get some nice tonal variation into your sound.

----

#### Record feedback

When you're operating in the 'crossfade loop' mode, you can change the record feedback parameter, using the 'Mixer -> Ext-Ring-Noise' knob on the synth:

![Record feedback](./resources/record-feedback.jpg)

‘Feedback’ controls the amount of feedback applied. At 0%, the new recording completely replaces the audio already in the buffer. At 100%, the new recording is layered on top of the old
audio. In other settings, the old audio is reduced in volume on each pass.

It allows you to record multiple layers on top of each other.

It might be helpful when you want to:

- record 2 different timbres so that they play both together. E.g. bass + lead
- record multiple notes, so that 1 single key on the keyboard is playing a chord

**Note!** All adjustable 'crossfade loop' parameters are reset after entering 'record' mode. That is done by intention. In the case of this parameter, remember the default value is '0' - no feedback. That is done to erase previously recorded data once the new recording is started. If the feedback is needed, **remember to enable it using the knob each time AFTER you've started the recording**.

----

### Volume

When you're operating in the 'crossfade loop' mode, you can change the volume of the synth, using the 'Mixer -> Sub Osc' knob on the synth:

![Volume](./resources/volume.jpg)

----

## One-shot samples

### Recording one-shot samples

Use the 'Oscillators -> Wave' switch to switch to the one-shot samples recording state:

![Recording one-shot samples](./resources/recording-one-shot-samples.jpg)

The positions have the following meanings:

- Sine wave - "crossfade loop" mode
- Square wave ( middle position ) - "one-shot samples" mode

The following workflow expected:

- Once you want to work with the one-shot samples - select the middle position of the mentioned switch
- Once you're in the "one-shot samples" mode, press any key on the keyboard to start recording that will be assigned to the selected key
- Simultaneously with that, provide some input from the microphone
- Release the key to stop the recording
- Press the same key once again to playback the recorded sample
- Repeat the same workflow for other keys, if that is needed

If you do not like what you've recorded and want to start from scratch - switch between modes - to 'crossfade loop' and then back to 'one-shot sample'. That will erase all previously recorded one-shot samples.

**Note!** This is a more simplistic mode. It does not have any additional effects. There is no even the volume adjustment. There are just the recording and the playback. Use the velocity to play with the different volumes. Use 'input controller' mic effects to record post-processed sounds.

----

Expand Down
4 changes: 3 additions & 1 deletion voice_synth/constants.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,11 +13,13 @@

# INSTRUMENT_SLOT_INDICES
CROSSFADE_LOOP_SYNTH_SLOT = 3
ONE_SHOT_AUGUSTUS_LOOP_INDEX = 0

# ROUTING
MASTER_CHANNEL = 0
MIC_ROUTE_CHANNEL = 4
SYNTH_INPUT_ROUTE_CHANNEL = 10
ONE_SHOT_CHANNEL = 48

# USED BASS STATION MIDI CC
NOVATION_REC_PRESSED = 81
Expand All @@ -37,6 +39,7 @@
NOVATION_IGNORED_4 = 56
NOVATION_MIXER_EXT_RING_NOISE = 24
NOVATION_MIXER_SUB_OSC = 22
NOVATION_SUB_OSC_WAVE = 80

# PLUGIN PARAMETERS
CROSSFADE_LOOP_SYNTH_RECORD_PARAM_INDEX = 37
Expand All @@ -52,4 +55,3 @@
CROSSFADE_LOOP_SYNTH_HARD_SYNC_DETUNE_PARAM_INDEX = 80
CROSSFADE_LOOP_SYNTH_FEEDBACK_PARAM_INDEX = 40
CROSSFADE_LOOP_SYNTH_VOLUME_PARAM_INDEX = 0

Loading

0 comments on commit 92820e9

Please sign in to comment.