public void GenerateWaveform(ClipData aud, NotReaper.Timeline timeline)
    {
        StopAllCoroutines();

        foreach (Transform child in transform)
        {
            GameObject.Destroy(child.gameObject);
        }

        if (timeline.tempoChanges.Count == 0)
        {
            return;
        }

        //Ensure all timestamps are different, otherwise texture generation is very crashy
        QNT_Timestamp lastTime = timeline.tempoChanges[0].time;

        for (int i = 1; i < timeline.tempoChanges.Count; ++i)
        {
            if (lastTime == timeline.tempoChanges[i].time)
            {
                return;
            }

            lastTime = timeline.tempoChanges[i].time;
        }

        var tempoChanges    = timeline.tempoChanges;
        int nextTempoChange = 1;

        List <GenerationSections> sections = new List <GenerationSections>();

        for (float t = 0; t < aud.length;)
        {
            float endOfSection = t + SecondsPerTexture;
            if (endOfSection > aud.length)
            {
                endOfSection = aud.length;
            }

            if (nextTempoChange < tempoChanges.Count)
            {
                float nextTempoChangeSec = timeline.TimestampToSeconds(tempoChanges[nextTempoChange].time);

                if (endOfSection >= nextTempoChangeSec)
                {
                    endOfSection = nextTempoChangeSec;
                    ++nextTempoChange;
                }
            }

            GenerationSections sec;
            sec.start = t;
            sec.end   = endOfSection;
            sections.Add(sec);

            t = endOfSection;
        }

        foreach (GenerationSections gen in sections)
        {
            int sampleStart = (int)(gen.start * aud.frequency * aud.channels);
            int sampleEnd   = (int)(gen.end * aud.frequency * aud.channels);

            QNT_Timestamp startTick = timeline.ShiftTick(new QNT_Timestamp(0), gen.start);
            UInt64        microsecondsPerQuarterNote = timeline.tempoChanges[timeline.GetCurrentBPMIndex(startTick)].microsecondsPerQuarterNote;

            float beatTime = Conversion.ToQNT(gen.end - gen.start, microsecondsPerQuarterNote).ToBeatTime();
            StartCoroutine(PaintWaveformSpectrum(aud.samples, sampleStart, sampleEnd - sampleStart, (int)(beatTime * PixelsPerQuarterNote), 64, NRSettings.config.waveformColor,
                                                 delegate(Texture2D tex) {
                GameObject obj      = GameObject.Instantiate(waveformSegmentInstance, new Vector3(0, 0, 0), Quaternion.identity, gameObject.transform);
                QNT_Timestamp start = timeline.ShiftTick(new QNT_Timestamp(0), gen.start);
                QNT_Timestamp end   = timeline.ShiftTick(new QNT_Timestamp(0), gen.end);

                obj.GetComponent <MeshFilter>().mesh = CreateMesh(start.ToBeatTime(), new QNT_Duration((UInt64)(end.tick - start.tick)).ToBeatTime(), 1);
                obj.GetComponent <MeshRenderer>().material.SetTexture("_MainTex", tex);
                obj.GetComponent <MeshRenderer>().enabled    = false;
                obj.GetComponent <Transform>().localPosition = new Vector3(0, -0.5f, 0);
                obj.GetComponent <Transform>().localScale    = new Vector3(1.0f, 1, 1);
            }
                                                 ));
        }
    }
 public override void UndoAction(Timeline timeline)
 {
     timeline.DeleteTargetFromAction(noteData);
 }
 public override void DoAction(Timeline timeline)
 {
     timeline.AddNoteFromAction(noteData);
 }
 public abstract void UndoAction(Timeline timeline);
 public override void UndoAction(Timeline timeline)
 {
     affectedNotes.ForEach(targetData => { timeline.AddNoteFromAction(targetData); });
 }
 public override void DoAction(Timeline timeline)
 {
     affectedNotes.ForEach(targetData => { timeline.DeleteTargetFromAction(targetData); });
 }