Weird editor bugs?

Okay, I feel like I’m losing my mind here.
I’m working on a very long and complex script. I’m trying to copy and paste code from one place to another. Before the paste, I can comment and uncomment blocks with alt /, and the auto-indent stuff works fine. But when I copy and paste a particular block of code, suddenly the editor refuses to comment with alt /, it loses its ability to auto-indent, I can’t enter blank lines with the enter key, etc.
Am I crazy here? Is there some explanation for this weird behavior? I’m trying to chase down and fix bugs in the code, but I’m spending my time trying to test whether the text editor has blown up.
Here’s the block of code in question:

          if envelopes[chosensound.to_sym] != nil
            puts "got an envelope for " + thissound.to_s
            cmd = "env handle "
            "param,attack,decay,sustain,release,startlevel,peaklevel,sustainlevel".split(",").each_with_index do |arg, i|
              if envelopes[chosensound.to_sym].split(",")[i] != nil
                cmd += ", " + envelopes[chosensound.to_sym].split(",")[i].to_s
              end #if
            end #each
            puts cmd
            eval cmd
          end #if there's an envelope
          

Very straightforward, and identical to another block earlier in the longer piece of code.
Why? What’s going on here?
Thanks for any doses of sanity. Sorely needed here. I’m so close to finishing up a major piece of code, when this is happening.

Here’s the entire script, fyi. NOT ready for prime time, but just to see about the editor bug.

##| arrange
##| allows user to arrange multiple samples to play in time with each other in a single function
##| uses a hashtable where the key is the sample and the value is a comma-delimited list of times.
##|   w,h,q,e,s for time divisions, d for dotted, t for triplet. Supports any number of dots.
##| Supports either individual samples or lists of samples (rings or arrays). If a ring or array,
##|   a sound is chosen randomly from the list.
##| kick = :bd_ada
##| snare = [:sn_dolf, :sn_dub, :sn_generic, :sn_zome]
##| hat = (ring :hat_bdu, :hat_cab, :hat_cats, :hat_gem, :hat_gnu)
##| use_bpm 120
##| arrangement = {kick =>"q,q,q,q", snare => "rq,h,q", hat => "qt,et,tq,te,qt,et,qt,et"}
##| 4.times do
##|   arrangesamples arrangement
##| end
##| arrangement = {kick =>"qd,qd,q", snare => "rq,hs,de", hat => "e,e,e,e,e,e,e,e"}
##| 4.times do
##|   arrangesamples arrangement
##| end

eval(File.open("C:\\Users\\harry\\Desktop\\Scripting\\SonicPi\\YummyFillings.rb", "r").read)



define :arrange do |arrangement, defaults, envelopes=nil, lfos=nil, trancegates=nil|
  timeline = {} #for the timing of notes
  melody = {} #for specified notes
  melody[nil] = nil #initialize with stub to simplify code
  settings = Hash.new #for instrument/sample-specific settings
  envelopes = ( envelopes == nil ? {} : envelopes )
  lfos = ( lfos == nil ? {} : lfos )
  trancegates = (trancegates == nil ? {} : trancegates )
  puts "envelopes"
  puts envelopes
  puts "lfos"
  puts lfos
  puts "trancegates"
  puts trancegates
  
  
  
  instruments = nil
  arrangement.each do |synthorsample, instr_times|
    puts " "
    puts " "
    puts "synthorsample " + synthorsample.to_s
    puts "instr_times: " + instr_times.to_s
    timetillnext = 0
    thistime = 0
    dots = 0
    triplets = 1
    takerest = false
    tonelist = Array.new
    
    
    thistone = nil
    thischord = nil
    thismode = nil
    oldtone = nil
    oldchord = nil
    oldmode = nil
    chordtone = nil
    
    instr_times.split(",").each_with_index do |thisnote, howmanytimes| #w, h, q, e, s w/possible suffix of t or d
      duration = ""
      puts "thisnote: " + thisnote.to_s
      puts "thistime: " + thistime.to_s
      oldtone = thistone
      oldchord = thischord
      oldmode = thismode
      thisdur, thistone, thischord, thismode = thisnote.split(" ")
      if thischord == nil and oldmode != nil and ["arp", "asc", "des", "ran"].include? oldmode[0..2]
        puts "grabbing old tone, chord, mode"
        thistone = oldtone
        thischord = oldchord
        thismode = oldmode
      end #if subbing in old chord and mode
      
      tonemode = thistone != nil
      chordmode = thischord != nil
      modemode = thismode != nil
      firsttone = nil
      
      puts "thisdur: " + thisdur.to_s
      puts "thistone: " + thistone.to_s
      puts "thischord: " + thischord.to_s
      puts "thismode: " + thismode.to_s
      puts "tonemode: " + tonemode.to_s
      puts "chordmode: " + chordmode.to_s
      puts "modemode: " + modemode.to_s
      
      thisdur.each_char do |letter|
        puts letter
        case letter.downcase
        when "r"
          takerest = true
        when "w"
          timetillnext += 4.0
        when "h"
          timetillnext += 2.0
        when "q"
          timetillnext += 1.0
        when "e"
          timetillnext += 0.5
        when "s"
          timetillnext += 0.25
        when "d"
          dots = dots + 1
        when "t"
          triplets = 2.0 / 3
        when /\d/
          puts "duration digit"
          duration += letter
        else
          puts letter + " is garbage, ignored"
        end #case letter
      end #each letter
      
      
      puts "raw duration: " + duration.to_s
      if duration.length > 0
        duration = duration.to_i
      else
        duration = 1
      end #if duration length > 0
      puts "cooked duration: " + duration.to_s
      
      timetillnext = timetillnext * duration * triplets * (2 - (0.5 ** dots))
      puts "timetillnext: " + timetillnext.to_s
      
      if chordmode
        puts "chordmode"
        puts "thistone: " + thistone.to_s
        if chordtone == nil
          puts "first tone!"
          chordtone = thistone
        end #if firsttone nil
        
        chordtone = ( chordtone[0] == ":" ? chordtone.delete_prefix(":").to_sym : chordtone.to_i )
        puts "chordtone: " + chordtone.to_s
        if chord_names.to_a.include? thischord
          puts "chord"
          thistone = chord chordtone, thischord
        else
          puts "scale"
          thistone = scale chordtone, thischord
        end #if chord or scale
        puts "thistone: " + thistone.to_s
        if modemode
          puts "modemode"
          puts "mode " + thismode[0..2]
          case thismode[0..2].downcase
          when "ran"
            puts "random"
            thistone = thistone.to_a.shuffle[howmanytimes]
          when "asc"
            puts "ascending arpeggio"
            thistone = thistone[howmanytimes]
          when "arp"
            puts "ascending arpeggio"
            thistone = thistone[howmanytimes]
          when "des"
            puts "descending arpeggio"
            thistone = thistone.to_a.reverse[howmanytimes]
          else
            puts "chord mode, leave chord intact"
          end #if in random mode
        end #if mode mode
        puts "thistone: " + thistone.to_s
      end #if chordmode
      
      
      
      
      
      
      if !takerest
        puts "scheduling note"
        if timeline.has_key?(thistime)
          puts "found key " + thistime.to_s
          timeline[thistime] << [synthorsample, timetillnext]
        else
          puts "did not find key " + thistime.to_s
          timeline[thistime] = [[synthorsample, timetillnext]]
        end #if haskey
        puts "timeline: " + timeline.to_s
        puts "thistone: " + thistone.to_s
        if tonemode
          tonelist  << thistone
          puts "tonelist: " + tonelist.to_s
          tonelist.each_with_index do |x, i|
            puts "tonelist[" + i.to_s + "]: " + x.to_s
          end #each
        else
          puts "this is a rest, carry thistime to next item in loop to delay start of note"
        end #if tonemode
        
      end #if !takerest
      
      
      
      
      thistime = thistime + timetillnext
      timetillnext = 0
      dots = 0
      triplets = 1
      takerest = false
      
    end #each note for this instrument
    if tonelist.length > 0
      puts "got tones, adding to melody hash"
      puts "melody: " + melody.to_s
      puts "synthorsample: " + synthorsample.to_s
      puts "tonelist: " + tonelist.to_s
      melody[synthorsample] = tonelist
      puts "melody: " + melody.to_s
    end
    
  end #each instrument
  
  #now traverse keys of the timeline, which are times, in order, and play samples at that time_warp
  puts " "
  puts " "
  puts " "
  puts " "
  
  
  puts "timeline keys sorted: " + timeline.keys.sort.to_s
  puts "melody: " + melody.to_s
  nextloop = 0
  maxtime = 0
  timeline.keys.sort.each do |thiskey|
    puts "thiskey: " + thiskey.to_s
    nextloop = nextloop + 1
    puts "next loop: " + nextloop.to_s + ", timeline length: " + timeline.length.to_s
    sleepytime = 0
    if timeline.length > nextloop then
      sleepytime = timeline.keys.sort[nextloop] - thiskey
      puts "not last loop."
      puts "next key: " + timeline.keys.sort[nextloop].to_s
      puts "sleepytime: " + sleepytime.to_s
      #the amount to rest is the duration between this time and next time
      #this even accounts for triplets vs 4s vs dots
    end #if
    
    
    thistime = timeline[thiskey]
    puts "thistime: " + thistime.to_s
    maxtime = 0
    thistime.each do |thissound|
      puts "thissound: " + thissound[0].to_s
      chosensound = thissound[0]
      if chosensound.is_a? Enumerable or chosensound.is_a? SonicPi::Core::RingVector
        chosensound = chosensound.choose
      end #if ring or array
      puts "chosensound: " + chosensound.to_s
      
      handle = nil #init here so it's scoped to be visible where needed
      
      
      if synth_names.to_a.include? chosensound
        puts "synth mode, getting note to play"
        thisnote = melody[thissound[0]]
        puts "thisnote: " + thisnote.to_s
        puts "melody[thissound[0]]: " + melody[thissound[0]].to_s
        melody[thissound[0]] = melody[thissound[0]].rotate #rotate note just played
        #need to add smarts for rings with fewer entries than notes played
        puts "thisnote: " + thisnote.to_s
        puts "thisnote[0]: " + thisnote[0].to_s
        if thisnote[0].is_a? String
          puts "thisnote[0] is a string"
          if thisnote[0] =~ /:.*/
            puts "got a colon, turning to symbol"
            cooknote = thisnote[0].delete_prefix(":").to_sym
            puts "thisnote: " + thisnote.to_s
          else
            puts "no colon, turning to int"
            cooknote = thisnote[0].to_i
          end
        else
          puts "thisnote[0] is a list/ring"
          cooknote = thisnote[0]
        end #if thisnote[0] is a string
        
        puts "converted thisnote: " + thisnote.to_s
        if defaults[thissound[0]] != nil
          
          mycmd = "use_synth_defaults " + defaults[thissound[0]]
          eval mycmd
        end
        
        
        with_synth chosensound do  handle = play cooknote end
        puts "testing for envelopes, lfos, trancegates"
        puts "thissound: " + thissound.to_s
        puts "chosensound: " + chosensound.to_s
        puts "envelopes[thissound.to_sym]: "
        puts envelopes[chosensound.to_sym]
        puts "lfos[thissound.to_sym]: "
        puts lfos[chosensound.to_sym]
        puts "trancegates[thissound.to_sym]: "
        puts trancegates[chosensound.to_sym]
        
        
        if envelopes[chosensound.to_sym] != nil
          puts "got an envelope for " + thissound.to_s
          cmd = "env handle "
          "param,attack,decay,sustain,release,startlevel,peaklevel,sustainlevel".split(",").each_with_index do |arg, i|
            if envelopes[chosensound.to_sym].split(",")[i] != nil
              cmd += ", " + envelopes[chosensound.to_sym].split(",")[i].to_s
            end #if
          end #each
          puts cmd
          eval cmd
        end #if there's an envelope
        
        if lfos[chosensound.to_sym] != nil
          puts "got an lfo for " + thissound.to_s
          cmd = "lfo handle "
          "param,duration,period,span,lfotype, delay,rampupperiods,rampdowntime, lfocurve".split(",").each_with_index do |arg, i|
            if lfos[chosensound.to_sym].split(",")[i] != nil
              cmd += ", " + lfos[chosensound.to_sym].split(",")[i].to_s
            end #if
          end #each
          puts cmd
          eval cmd
        end #if there's an lfo
        
        if trancegates[chosensound.to_sym] != nil
          puts "got a trancegate for " + thissound.to_s
          cmd = "trancegate handle "
          "duration,period,gutter,delay,maxvol,minvol,lfotype,curve".split(",").each_with_index do |arg, i|
            if trancegates[chosensound.to_sym].split(",")[i] != nil
              cmd += ", " + trancegates[chosensound.to_sym].split(",")[i].to_s
            end #if
          end #each
          puts cmd
          eval cmd
        end #if there's a trancegate
        
        
        
      else
        puts "sample mode"
        puts "melody: " + melody.to_s
        puts "thissound: " + thissound.to_s
        puts "melody[thissound]: " + melody[thissound[0]].to_s
        if melody[thissound[0]] != nil
          puts "got a melody, picking thisnote"
          thisnote = melody[thissound[0]]
          puts "thisnote: " + thisnote.to_s
          puts "melody[thissound[0]]: " + melody[thissound[0]].to_s
          melody[thissound[0]] = melody[thissound[0]].rotate #rotate note just played
          #need to add smarts for rings with fewer entries than notes played
          puts "thisnote: " + thisnote.to_s
          puts "thisnote[0]: " + thisnote[0].to_s
          
          if defaults[thisnote[0]] != nil
            
            mycmd = "use_sample_defaults " + defaults[thisnote[0]]
            eval mycmd
          end
          
          
          if thisnote[0].is_a? String
            puts "thisnote[0] is a string"
            if thisnote[0] =~ /:.*/
              puts "got a colon, turning to symbol"
              thisnote = thisnote[0].delete_prefix(":").to_sym
            else
              puts "no colon, turning to int"
              thisnote = thisnote[0].to_i
            end
            
            pitch_stretch_ratio = midi_to_hz(60 + thisnote) / midi_to_hz(60)
            sample chosensound, pitch_stretch: thissound[1].to_i * pitch_stretch_ratio, rpitch: thisnote
            
          else
            puts "thisnote[0] is a list/ring"
            thisnote[0].each do |onenote|
              puts "onenote: " + onenote.to_s
              pitch_stretch_ratio = midi_to_hz(60 + onenote) / midi_to_hz(60)
              sample chosensound, pitch_stretch: thissound[1].to_i * pitch_stretch_ratio, rpitch: onenote
            end #each note
            
          end #if thisnote[0] is a string
        else
          
          
          puts "no note, play sample raw"
          
          #need to add code for pitch shifting samples
          handle = sample chosensound
          
          puts "testing for envelopes, lfos, trancegates"
          puts "thissound: " + thissound.to_s
          puts "chosensound: " + chosensound.to_s
          puts "envelopes[thissound.to_sym]: "
          puts envelopes[chosensound.to_sym]
          puts "lfos[thissound.to_sym]: "
          puts lfos[chosensound.to_sym]
          puts "trancegates[thissound.to_sym]: "
          puts trancegates[chosensound.to_sym]
          
          if envelopes[chosensound.to_sym] != nil
            puts "got an envelope for " + thissound.to_s
            cmd = "env handle "
            "param,attack,decay,sustain,release,startlevel,peaklevel,sustainlevel".split(",").each_with_index do |arg, i|
              if envelopes[chosensound.to_sym].split(",")[i] != nil
                cmd += ", " + envelopes[chosensound.to_sym].split(",")[i].to_s
              end #if
            end #each
            puts cmd
            eval cmd
          end #if there's an envelope
          
          
          if lfos[chosensound.to_sym] != nil
            puts "got an lfo for " + thissound.to_s
            cmd = "lfo handle "
            "param,duration,period,span,lfotype, delay,rampupperiods,rampdowntime, lfocurve".split(",").each_with_index do |arg, i|
              if lfos[chosensound.to_sym].split(",")[i] != nil
                cmd += ", " + lfos[chosensound.to_sym].split(",")[i].to_s
              end #if
            end #each
            puts cmd
            eval cmd
          end #if there's an lfo
          
          
          
          
          
          
          
          
        end #if got a note
      end #if melody note not nil
      
      puts "this sound time: " + thissound[1].to_s
      maxtime = [thissound[1], maxtime].max
      puts "maxtime: " + maxtime.to_s
      sleepytime = maxtime if timeline.length == nextloop
    end #each sound
    puts "sleepytime: " + sleepytime.to_s
    sleep sleepytime
  end #thistime
end #define






kick = :bd_ada
snare = [:sn_dolf, :sn_dub, :sn_generic, :sn_zome]
hat = (ring :hat_bdu, :hat_cab, :hat_cats, :hat_gem, :hat_gnu)
bass = :bass_foundation

test = :ambi_drone

use_bpm 120
##| arrangement = {bass => "q :e3 m7 asc,q,q,q", kick =>"q,q,q,q", snare => "rq,h,q", hat => "qt,et,tq,te,qt,et,qt,et"}
##| arrangement = {bass => "q :e3 m7 rand,q,q,q"}

arrangement = {test => "4w"}
defaults = {test => "cutoff: 70, release: 0.25, sustain: 4"}
envelopes =  { test => "'amp',16" }
lfos = nil
trancegates =  nil

arrange arrangement, defaults, envelopes, lfos, trancegates





Line 412 is where the trouble is.

It may be that you have reached the limit for the amount of text the editor can handle. (This is set by the max udp packet size that can be sent) this will cause the symptoms you are getting. I often work with very long files which experience this)
The solution is to work with an editor like Microsoft visual code editor. (Available on most platforms) save your code after edit and use run_file “path-to-your-file name” as the code in your sp buffer to run it.

1 Like

Yeah, that makes sense.
Thanks, I’ll try that.

1 Like