Madwin74

Boss SL-2 Slicer Emulator

May 17th, 2023
851
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C# 8.20 KB | Source Code | 0 0
  1. /***********************************************************
  2.  ***********************************************************
  3.  **                                                       **
  4.  **   Codesnippets written by Madwin for MMP 2023         **
  5.  **                                                       **
  6.  **   Not to be used freely. the code still has errors    **
  7.  **   It's intended to be used as starting point.         **
  8.  **   Code has not been checked and might still need      **
  9.  **   (a lot of) work.                                    **
  10.  **                                                       **
  11.  **   ℗ & © MadMedia Productions 2023                     **
  12.  **                                                       **
  13.  ***********************************************************
  14.  ***********************************************************
  15.  **                                                       **
  16.  **   -- Disclaimer: --                                   **
  17.  **                                                       **
  18.  **   If code is used in private projects and/or for      **
  19.  **   study purposes please mention resource. Any other   **
  20.  **   use -whether commercial or non-commercial- is not   **
  21.  **   condoned by the author and violates his intent.     **
  22.  **                                                       **
  23.  **   [email protected]                             **
  24.  **                                                       **
  25.  ***********************************************************
  26.  ***********************************************************/
  27.  
  28.  
  29.  
  30. using CSCore;
  31. using CSCore.Codecs.WAV;
  32. using CSCore.DSP;
  33. using CSCore.SoundIn;
  34. using CSCore.Streams;
  35. using System;
  36.  
  37. public enum SlicerMode
  38. {
  39.     Single,
  40.     Dual,
  41.     Tremolo,
  42.     Harmonica,
  43.     SFX
  44. }
  45.  
  46. public class SlicerEmulator
  47. {
  48.     private const int BufferSize = 8192;
  49.  
  50.     private ISoundIn soundIn;
  51.     private IWaveSource waveSource;
  52.     private ISampleSource sampleSource;
  53.  
  54.     private BiQuadFilter[] filters;
  55.     private WaveBuffer buffer;
  56.  
  57.     public bool IsEnabled { get; set; }
  58.     public float Level { get; set; }
  59.     public float Rate { get; set; }
  60.     public float Depth { get; set; }
  61.     public float Balance { get; set; }
  62.     public float Tempo { get; set; }
  63.     public float Attack { get; set; }
  64.     public float Duty { get; set; }
  65.     public float Variaties { get; set; }
  66.     public SlicerMode Mode { get; set; }
  67.  
  68.     public SlicerEmulator()
  69.     {
  70.         IsEnabled = false;
  71.         Level = 0.5f;
  72.         Rate = 1.0f;
  73.         Depth = 0.5f;
  74.         Balance = 0.0f;
  75.         Tempo = 1.0f;
  76.         Attack = 0.5f;
  77.         Duty = 0.5f;
  78.         Variaties = 0.5f;
  79.         Mode = SlicerMode.Single;
  80.  
  81.         filters = new BiQuadFilter[2];
  82.         filters[0] = BiQuadFilter.LowpassFilter(44100, 10000, 0.707f);
  83.         filters[1] = BiQuadFilter.HighpassFilter(44100, 100, 0.707f);
  84.  
  85.         buffer = new WaveBuffer(BufferSize);
  86.     }
  87.  
  88.     public void Initialize()
  89.     {
  90.         soundIn = new WasapiCapture();
  91.         soundIn.Initialize();
  92.  
  93.         soundIn.DataAvailable += SoundIn_DataAvailable;
  94.  
  95.         waveSource = soundIn.ToSampleSource().ToStereo();
  96.         sampleSource = waveSource.ToWaveSource();
  97.  
  98.         soundIn.Start();
  99.     }
  100.  
  101.     public void Stop()
  102.     {
  103.         soundIn.Stop();
  104.         soundIn.Dispose();
  105.     }
  106.  
  107.     private void SoundIn_DataAvailable(object sender, DataAvailableEventArgs e)
  108.     {
  109.         var count = e.ByteCount / 4; // 4 bytes per float sample
  110.         sampleSource.Read(buffer, 0, count);
  111.  
  112.         var balance = (Balance + 1.0f) / 2.0f;
  113.         var leftDelayTime = 0.003f + balance * 0.004f;
  114.         var rightDelayTime = 0.003f + (1.0f - balance) * 0.004f;
  115.  
  116.         var rate = Rate * 10.0f;
  117.         var depth = Depth * 0.5f;
  118.         var level = Level * 0.5f;
  119.  
  120.         var offset = (float)(Math.Sin(rate * Math.PI * sampleSource.Position / sampleSource.Length) * depth);
  121.  
  122.         for (int i = 0; i < count; i += 2)
  123.         {
  124.             var inputLeft = buffer.ShortBuffer[i] / 32768f;
  125.             var inputRight = buffer.ShortBuffer[i + 1] / 32768f;
  126.  
  127.             var leftOutput = inputLeft;
  128.             var rightOutput = inputRight;
  129.  
  130.             // Apply slicing effect based on the selected mode
  131.             switch (Mode)
  132. {
  133. case SlicerMode.Single:
  134. leftOutput = ProcessSingle(inputLeft, offset, level);
  135. rightOutput = ProcessSingle(inputRight, offset, level);
  136. break;
  137. case SlicerMode.Dual:
  138. leftOutput = ProcessDual(inputLeft, offset, level, leftDelayTime, rightDelayTime);
  139. rightOutput = ProcessDual(inputRight, offset, level, rightDelayTime, leftDelayTime);
  140. break;
  141. case SlicerMode.Tremolo:
  142. leftOutput = ProcessTremolo(inputLeft, offset, level, leftDelayTime, rightDelayTime);
  143. rightOutput = ProcessTremolo(inputRight, offset, level, rightDelayTime, leftDelayTime);
  144. break;
  145. case SlicerMode.Harmonica:
  146. leftOutput = ProcessHarmonica(inputLeft, offset, level, leftDelayTime, rightDelayTime);
  147. rightOutput = ProcessHarmonica(inputRight, offset, level, rightDelayTime, leftDelayTime);
  148. break;
  149. case SlicerMode.SFX:
  150. leftOutput = ProcessSFX(inputLeft, offset, level, leftDelayTime, rightDelayTime);
  151. rightOutput = ProcessSFX(inputRight, offset, level, rightDelayTime, leftDelayTime);
  152. break;
  153. }
  154.  
  155.  
  156.  
  157.         buffer.ShortBuffer[i] = (short)(leftOutput * 32768f);
  158.         buffer.ShortBuffer[i + 1] = (short)(rightOutput * 32768f);
  159.     }
  160.  
  161.     e.Data = buffer.ByteBuffer;
  162. }
  163.  
  164. private float ProcessSingle(float input, float offset, float level)
  165. {
  166.     var output = input + offset * level;
  167.     return output;
  168. }
  169.  
  170. private float ProcessDual(float input, float offset, float level, float delayTime1, float delayTime2)
  171. {
  172.     var delayed1 = filters[0].Process(input);
  173.     var delayed2 = filters[1].Process(input);
  174.  
  175.     var output = input + offset * level * (1.0f - delayTime1) + delayed1 * level * delayTime1 + delayed2 * level * delayTime2;
  176.     return output;
  177. }
  178.  
  179. private float ProcessTremolo(float input, float offset, float level, float delayTime1, float delayTime2)
  180. {
  181.     var delayed1 = filters[0].Process(input);
  182.     var delayed2 = filters[1].Process(input);
  183.  
  184.     var tremoloRate = 4.0f * Tempo;
  185.     var tremoloDepth = 0.5f * Variaties;
  186.  
  187.     var tremoloOffset = (float)(Math.Sin(tremoloRate * Math.PI * sampleSource.Position / sampleSource.Length) * tremoloDepth);
  188.  
  189.     var output = input + (offset + tremoloOffset) * level * (1.0f - delayTime1) + delayed1 * level * delayTime1 + delayed2 * level * delayTime2;
  190.     return output;
  191. }
  192.  
  193. private float ProcessHarmonica(float input, float offset, float level, float delayTime1, float delayTime2)
  194. {
  195.     var harmonicaRate = 0.5f * Tempo;
  196.     var harmonicaDepth = 0.2f * Variaties;
  197.  
  198.     var harmonicaOffset = (float)(Math.Sin(harmonicaRate * Math.PI * sampleSource.Position / sampleSource.Length) * harmonicaDepth);
  199.  
  200.     var output = input + (offset + harmonicaOffset) * level * (1.0f - delayTime1) + input * level * delayTime1 + input * level * delayTime2;
  201.     return output;
  202. }
  203.  
  204. private float ProcessSFX(float input, float offset, float level, float delayTime1, float delayTime2)
  205. {
  206. var sfxRate = 2.0f * Tempo;
  207. var sfxDepth = 0.8f * Variaties;
  208.  
  209.  
  210.  
  211.     var sfxOffset = (float)(Math.Sin(sfxRate * Math.PI * sampleSource.Position / sampleSource.Length) * sfxDepth);
  212.  
  213.     var output = input + (offset + sfxOffset) * level * (1.0f - delayTime1) + input * level * delayTime1 + input * level * delayTime2;
  214.     return output;
  215. }
  216.  
  217. }
  218.  
  219.  
  220.  
  221. /*
  222. The `SlicerEmulator` class includes the controls: `Balance` for adjusting the stereo balance, `Tempo` for
  223. controlling the tempo of the effect, `Attack` for setting the attack time, `Duty` for adjusting the duty
  224. cycle, and `Variaties` for controlling variations in the effect. It also introduces five different modes:
  225. `Single`, `Dual`, `Tremolo`, `Harmonica`, and `SFX`, each with its own processing logic.
  226.  
  227. The class processes the audio in real-time, handling the input and output through the `SoundIn_DataAvailable`
  228. event. The processed audio is then assigned back to the `Data` property of the `DataAvailableEventArgs` object.
  229.  
  230. Remember to include the necessary dependencies and configure the audio input and output accordingly in
  231. your application to make use of this class effectively.
  232. */
Advertisement
Add Comment
Please, Sign In to add comment