Simple sampler/step Seq, 1 digit out!

Hi,

I’ve made a super simple 16 step sequencer (for no real reason at all), it’s not quite perfect, I’ve used an array of bools that gets iterated over using a counter, I suspect I’m one digit off somewhere, or I need to shift the array by a digit. If anyone could take a look and see if they can spot the problem that would be amazing and I am welcome to any suggestions or feedback for general improvement.

using UnityEngine;
using System.Collections;
using System;

public class Sampler16 : MonoBehaviour {

    public float bpm = 120;
    public float beatSegment = 16;
    private double nextEventTime;
    private int flip = 0;
    private bool running = false;

    //public AudioClip[] clips = new AudioClip[2];
    public AudioClip[] kick;
    public AudioClip[] snare;
    public AudioClip[] hiHat;
    public AudioClip[] bassOneShot;
    AudioClip[] openHat;
    AudioClip[] chordOneShot;
    private AudioSource[] audioSources = new AudioSource[4];
    public int counter = 0;
    public bool[] myHiBools = new bool[16];
    public bool[] myKikBools = new bool[16];
    public bool[] mySnrBools = new bool[16];
    public bool[] myBassBools = new bool[16];
    // Use this for initialization
    void Start () {
       
            GameObject child = new GameObject ("Player");
            child.transform.parent = gameObject.transform;
            audioSources[0] = child.AddComponent<AudioSource> ();
            audioSources[1] = child.AddComponent<AudioSource> ();
            audioSources[2] = child.AddComponent<AudioSource> ();
            audioSources[3] = child.AddComponent<AudioSource> ();
            nextEventTime = AudioSettings.dspTime + 2.0f;
            running = true;
    }
   
    // Update is called once per frame
    void Update () {
        if (!running)
            return;

        double time = AudioSettings.dspTime;
        if (time + 1.0f > nextEventTime)
        {
        //    audioSources.clip = kick[0];
        //    audioSources.PlayScheduled (nextEventTime);
        //    Debug.Log ("Scheduled source to start at time " + nextEventTime);
            Counter ();
            PlayStuff();
            nextEventTime += (60.0f / bpm) * beatSegment;
        }
    }

    void Counter() {

        counter = counter + 1;
        if (counter > 15) {
            counter = 0;
        }
        Debug.Log (counter);
    }

    void PlayStuff(){

        for (int i = 0; i < counter; i++)
        {
            if (myHiBools[counter] == true) {
                PlayHiHat (0);
                    }
            if (mySnrBools[counter] == true) {
                PlaySnare(0);
            }

            if (myKikBools[counter] == true) {
                PlayKick(0);
            }

            if (myBassBools[counter] == true) {
                PlayBass(0);
            }
        }
    }
    void PlayKick (int clip)

    {
        AudioSource audio1 = audioSources[0];
        audio1.clip = kick[clip];
        audio1.Play ();
    }

    void PlaySnare (int clip)

    {
        AudioSource audio2 = audioSources[1];
        audio2.clip = snare[clip];
        audio2.Play ();
    }

    void PlayHiHat (int clip)

    {
        AudioSource audio3 = audioSources[2];
        audio3.clip = hiHat[clip];
        audio3.Play ();
    }

    void PlayBass (int clip)

    {
        AudioSource audio4 = audioSources[3];
        audio4.clip = bassOneShot[clip];
        audio4.Play ();
    }
       
}

Ideally I’d like the boolean arrays to appear Horizontal instead of vertical, but that’s only a superficial improvement so non important.

Also I’ve created four different audio sources for the elements, would it be simple enough to expose the volume control from each of the sources in the public variables bit?

Don’t worry I think i solved it with this I knew I was a digit out:

if (myBools[counter-1] == true)

Now for the next little pieces of fun! I know the audio sources are now the children of the gameObject, can I get/set their volumes before they are instantiated? Or expose their volume slider in this script?

Actually scrap that, the way I had it was still a bodge, I get an Index out of range exception when I get to 17, i thought that would be a fine way to fix it but I get a stutter slight drop in timing. I could be being over the top, but I think it’s causing the loop to choke a little bit.

Here’s the whole code, i got bored and stuck an arpeggio in their as well, all for no reason so I hope someone might enjoy!

using UnityEngine;
using System.Collections;
using System;
using ForieroEngine.MIDIUnified;

public class Sampler16 : MonoBehaviour {

    public float bpm = 120;
    public float beatSegment = 16;
    private double nextEventTime;
    private int flip = 0;
    private bool running = false;

    //public AudioClip[] clips = new AudioClip[2];
    public AudioClip[] kick;
    public AudioClip[] snare;
    public AudioClip[] hiHat;
    public AudioClip[] bassOneShot;
    AudioClip[] openHat;
    AudioClip[] chordOneShot;
    private AudioSource[] audioSources = new AudioSource[4];
    public int counter = 0;
    public bool[] myHiBools = new bool[16];
    public bool[] myKikBools = new bool[16];
    public bool[] mySnrBools = new bool[16];
    public bool[] myBassBools = new bool[16];
    public bool[] myArpBools = new bool[16];
    public int numNotes = 16;
    public int arpCounter;
    public int arpNotes = 4;
    private int noteVal;
    private int[] majorScale = new int[] {0,2,4,5,7,9,11};
    private int[] pentaScale = new int[] {0,2,4,7,9,12,14,16,19,21,24, 26, 28, 29, 31, 32, 33, 34};
    private int scaleOffset = 60;
    public int scaleIndex = 1;
    public float delay;

    void Awake ()
    {
        MidiOut.ShortMessageEvent += ShortMessage;
    }

    // Use this for initialization
    void Start () {
      
            GameObject child = new GameObject ("Player");
            child.transform.parent = gameObject.transform;
            audioSources[0] = child.AddComponent<AudioSource> ();
            audioSources[1] = child.AddComponent<AudioSource> ();
            audioSources[2] = child.AddComponent<AudioSource> ();
            audioSources[3] = child.AddComponent<AudioSource> ();
            nextEventTime = AudioSettings.dspTime + 2.0f;
            running = true;
    }
  
    // Update is called once per frame
    void Update () {
        if (!running)
            return;

        double time = AudioSettings.dspTime;
        if (time + 1.0f > nextEventTime)
        {
        //    audioSources.clip = kick[0];
        //    audioSources.PlayScheduled (nextEventTime);
        //    Debug.Log ("Scheduled source to start at time " + nextEventTime);
            Counter ();
            ArpCounter ();
            PlayStuff();
            nextEventTime += (60.0f / bpm) * beatSegment;
        }
    }

    void Counter() {


        if (counter > numNotes) {
            counter = 0;
        } else {
            counter = counter + 1;
        }
        Debug.Log (counter);
    }

    void ArpCounter() {

        arpCounter = arpCounter + 1;
        if (arpCounter > arpNotes) {
            arpCounter = 0;
        }
    //    Debug.Log (arpCounter);
    }

    void PlayStuff(){

        for (int i = 0; i < counter; i++)
        {
            if (myHiBools[counter-1] == true) {
                PlayHiHat (0);
                    }
            if (mySnrBools[counter-1] == true) {
                PlaySnare(0);
            }

            if (myKikBools[counter-1] == true) {
                PlayKick(0);
            }

            if (myBassBools[counter-1] == true) {
                PlayBass(0);
            }

            if (myArpBools[counter-1] == true) {
                //Arppeggio ();
                noteVal = pentaScale[arpCounter] + scaleOffset;
                MidiOut.NoteOn (noteVal, 88, 0);
                StartCoroutine (Arppeggio (delay));
            }
        }
    }

    IEnumerator Arppeggio(float delay)
    {
        WaitForSeconds wait = new WaitForSeconds (delay);
        yield return wait;
        MidiOut.NoteOff (noteVal);
    }

    void OnEnable ()
    {
        MidiOut.ShortMessageEvent += ShortMessage;
    }

    void OnDisable ()
    {
        MidiOut.ShortMessageEvent -= ShortMessage;
    }

    void ShortMessage (int Command, int Data1, int Data2)
    {
        if (Command.ToMidiCommand () == 144 && Data1 == noteVal) {
            //    rb.AddForce (new Vector3 (0, impulseForce, 0), ForceMode.Impulse);
        }

        if (Command.ToMidiCommand () == 128 && Data1 == noteVal) {

        }
    }


    void PlayKick (int clip)

    {
        AudioSource audio1 = audioSources[0];
        audio1.clip = kick[clip];
        audio1.Play ();
    }

    void PlaySnare (int clip)

    {
        AudioSource audio2 = audioSources[1];
        audio2.clip = snare[clip];
        audio2.Play ();
    }

    void PlayHiHat (int clip)

    {
        AudioSource audio3 = audioSources[2];
        audio3.clip = hiHat[clip];
        audio3.Play ();
    }

    void PlayBass (int clip)

    {
        AudioSource audio4 = audioSources[3];
        audio4.clip = bassOneShot[clip];
        audio4.Play ();
    }
      
}

Sadly you have to have that Foreiro Midi package (for the arp bit to work), it’s worth it if you’re like me and into the whole making music in Unity because you’re bored of DAW’s and want a change of scenery! :stuck_out_tongue:

1 Like