Page 1 of 1

Opus Magnificus for iPad version 1

Posted: Thu Oct 29, 2015 10:00 am
by Henko
This program generates random "music" (if the term "music" is applyable in this case).
The generator contains 9 melody channels and one drum channel.

Each melody channel may be assigned either an instrument group or a dedicated instrument. When an instrument group is assigned, the channel will choose instruments at random from time to time from that group. Further ranges with respect to notes, octaves, speed, and volume for that channel must be specified in a channel window, from which the program is allowed to generate tones, speed and volume commands.

There are 2 methods to generate drum sounds for channel 10: a random drum generator, which is operational in this version and a "drum machine", such as found on synthezisers. The latter is not operational yet, but will added to the next (and probably the last) version.

Upon running the program, a simple screen will appear with 9 melody buttons and 2 Drum buttons. 4 (pre-loaded) Melody channels are playing. These 4 can be muted ore set "free" when desired.

MELODY WINDOW: Touching one of the 9 melody channels opens the melody window for that channel.
Touching the 'Instrument group' or 'Instrument' button will provide a list with groups or instruments from which a group or instrument can be chosen for this channel. Furthermore the notes, octaves, and speeds from which the program may choose, can be set. The minimum and maximum volume for this channel are set using the sliders (set the maximum volume first, then the minumum volume).
Important: all elements need at least one vallue set, to enable the generating process.
At the bottom of the window a number of buttons appear:
"Apply" : apply the settings and play the music while the melody window remains active.
"Default": fills the window with pre-defined settings (which may be changed in the 'app_init' function).
"Reset": clears the settings in the window. The window remains active.
"Mute": a toggle switch to mute or revive the channel, while keeping the settings. The window closes upon muting the channel.
"Free": the settings are cleared, the window closes. The channel is free for another use.
The window can be closed by touching the cross in the right upper corner. Te music will restart with the new/modified settings. If the window does not close, then chech for completeness of the settings (including the volume sliders and the 'Mute' button).

DRUM RANDOM WINDOW: one or two drum instruments may be chosen touching the corresponding buttons. A list will pop up from which a drum instrument can be chosen. For each instrument, the speeds and volume can be indicated, that the program is allowed to use for generating a drum stream for channel 10.
If 2 instruments are specified, they will play sequentially, not synchronous as the drum machine will do. The drum channel may be muted and revived using the 'Mute' button.

All settings are kept in the CHAN(11,36) array, with the following format:
Rows: row 0 contains the default settings
row 1 through 9 contain the melody settings
row 10 contains the drum setting for channel 10
Columns:
0 : channel active or not (1/0)
1 : instrument group number or drum1 number (0-15 or 0-46)
2 : instrument number or drum2 number (0-127 or 0-46
3-5 : reserved
6-17 : notes for each note button (1/0)
18-25 : octaves setting for melody or speed settings for drum1 (1/0)
26-33 : speed setting for melody or drum2 (1/0)
34 : minimum volume setting (0-127, but <= than max.)
35 : maximum volum setting (0-127, but >= than min.)

Code: Select all

' Opus Magnificus for iPad, a music generator
' version 1.0
' coded bij Henko, october 2015
'
dim chan(11,36),group$(16),melody$(128),n$(11)
dim drum$(47),notes$(12),drum_not$(47),prim(7),sec(5)
app_init
new_song:
notes set n$(1),n$(2),n$(3),n$(4),n$(5),n$(6),n$(7),n$(8),n$(9),n$(10)
notes play
for ch=1 to 9 ! n$(ch)=notes_gen$(ch) ! next ch ! n$(10)=drum_gen$()
go_on: slowdown
for ch=1 to 9
  if bp("c"&ch)then
    channel(ch) ! n$(ch)=notes_gen$(ch) ! goto new_song
    end if
  next ch
if bp("c10") then ! drums() ! n$(10)=drum_gen$() ! goto new_song ! end if
' if bp("debug") then debug pause              /*  debug  */
if notes_time()<.4*notes_length() then go_on else new_song
end 

def channel(ch)
dim c(36)
page_open("channel")
ch_start:
for i=0 to 35 ! c(i)=.chan(ch,i) ! next i     ' load channel setting
if c(1)=-1 and c(2)=-1 then ! titel$="Free"   ' set window title
  else
  if c(1)>=0 then
    titel$=.group$(c(1))
    else ! titel$=.melody$(c(2))
    end if
  end if
button "title" text titel$
for i=0 to 11                                   ' set note buttons
  if c(6+i) then no$=.check$ else no$=.notes$(i)
  button "n"&i text no$
  next i
for i=1 to 8                                   ' set octave buttons
  if c(17+i) then oct$=.check$ else oct$=i
  button "o"&i text oct$
  next i
for i=1 to 8                                   ' set speed buttons
  if c(25+i) then sp$=.check$ else sp$=2^(i-1)
  button "s"&i text sp$
  next i
slider "volmin" value c(34)/127                ' set volume sliders
slider "volmax" value c(35)/127
if c(0) then mut$="Mute" else mut$="Muted"     ' set mute button
button "mute" text mut$
change: slowdown
if bp("gt") then                              ' select instrument group
  c(2)=-1
  page_open("group")
  g_wait1: k=list_selected("group") ! if k=-1 then g_wait1
  button "c"&ch text .group$(k)
  button "title" text .group$(k)
  c(1)=k ! list "group" select -1
  page_close("group")
  end if
if bp("it") then                              ' select instrument
  c(1)=-1
  page_open("melody")
  g_wait2: k=list_selected("melody") ! if k=-1 then g_wait2
  button "c"&ch text .melody$(k)
  button "title" text .melody$(k)
  c(2)=k ! list "melody" select -1
  page_close("melody")
  end if
for i=0 to 11                                   ' select notes
  if not bp("n"&i) then continue
  c(6+i)=1-c(6+i)
  if c(6+i) then no$=.check$ else no$=.notes$(i)
  button "n"&i text no$
  next i
for i=1 to 8                                   ' select octaves
  if not bp("o"&i) then continue
  c(17+i)=1-c(17+i)
  if c(17+i) then oct$=.check$ else oct$=i
  button "o"&i text oct$
  next i
for i=1 to 8                                   ' select speed
  if not bp("s"&i) then continue
  c(25+i)=1-c(25+i)
  if c(25+i) then sp$=.check$ else sp$=2^(i-1)
  button "s"&i text sp$
  next i
if slider_changed("volmin") then               ' select minimum volume
  c(34)=floor(min(127*slider_value("volmin"),c(35)))
  slider "volmin" value c(34)/127
  end if
if slider_changed("volmax") then               ' select maximum volume
  c(35)=floor(max(127*slider_value("volmax"),c(34)))
  slider "volmax" value c(35)/127
  end if
if bp("mute") then                             ' select Mute button
  c(0)=1-c(0)
  if c(1)>=0 then mus$=.group$(c(1))
  if c(2)>=0 then mus$=.melody$(c(2))
  if c(0) then
    mut$="Mute"
    else
    mut$="Muted" ! mus$="("&mus$&")"
    end if
  button "mute" text mut$ ! button "c"&ch text mus$
  if not c(0) then
    for i=0 to 35 ! .chan(ch,i)=c(i) ! next i    ' save channel settings
    goto back
    end if
  end if
if bp("fre") then                              ' select Free button
  c(0)=0 ! c(1)=-1 ! c(2)=-1
  for i=3 to 35 ! c(i)=0 ! next i
  button "c"&ch text "Free"
  for i=0 to 35 ! .chan(ch,i)=c(i) ! next i    ' save channel settings
  goto back
  end if
if bp("res") then                              ' select Reset button
  for i=3 to 35 ! .chan(ch,i)=0 ! next i
  goto ch_start
  end if
if bp("def") then                              ' select Default button
  for i=0 to 35 ! c(i)=.chan(0,i) ! next i
  if c(1)>=0 then mus$=.group$(c(1)) else mus$=.melody$(c(2))
  button "c"&ch text mus$
  goto ch_start
  end if
if bp("apl") then                              ' select Apply button
  if check_ok(c)=0 then change
  for i=0 to 35 ! .chan(ch,i)=c(i) ! next i
  .n$(ch)=notes_gen$(ch)
  notes set .n$(1),.n$(2),.n$(3),.n$(4),.n$(5),.n$(6),.n$(7),.n$(8),.n$(9),.n$(10)
  notes play ! goto change
  end if
if bp("close") then                            ' select Close button
  for i=0 to 35 ! .chan(ch,i)=c(i) ! next i    ' save channel settings
  if c(0)=0 then back
  if c(1)=-1 and c(2)=-1 then back
  if check_ok(c)=1 then back
  end if
' if bp("debug") then debug pause              /*  debug  */
goto change
back:
page_close("channel") ! return
end def

def check_ok(a())
ok=0
for i=6 to 17 ! if a(i) then ! ok=1 ! break ! end if ! next i
if ok then ok=0 else return 0        ' no notes
for i=18 to 25 ! if a(i) then ! ok=1 ! break ! end if ! next i
if ok then ok=0 else return 0        ' no octaves
for i=26 to 33 ! if a(i) then ! ok=1 ! break ! end if ! next i
if not ok then return 0        ' no speed
if a(35)=0 then return 0       ' no volume
return 1
end def

def drums()
dim c(36)
page_open("drumwin")
for i=0 to 35 ! c(i)=.chan(10,i) ! next i     ' load channel setting
for i=1 to 8                                   ' set speed1 buttons
  if c(17+i) then sp$=.check$ else sp$=2^(i-1)
  button "d_s1"&i text sp$
  next i
for i=1 to 8                                   ' set speed2 buttons
  if c(25+i) then sp$=.check$ else sp$=2^(i-1)
  button "d_s2"&i text sp$
  next i
slider "d_volmin" value c(34)/127                ' set volume sliders
slider "d_volmax" value c(35)/127
if c(0) then mut$="Mute" else mut$="Muted"     ' set mute button
button "d_mute" text mut$
change: slowdown
d=0 ! if bp("dr1") then ! d=1 ! else if bp("dr2") then d=2 ! end if
if d then
  page_open("drums")
  button "c10" text "Drums random" ! button "d_title" text "Drums"
  d_wait1: k=list_selected("drums") ! if k=-1 then d_wait1
  button "dr"&d text .drum$(k)
  c(d)=k ! list "drums" select -1
  page_close("drums")
  end if
for i=1 to 8                                 ' select speed 1
  if not bp("d_s1"&i) then continue
  c(17+i)=1-c(17+i)
  if c(17+i) then sp$=.check$ else sp$=2^(i-1)
  button "d_s1"&i text sp$
  next i
for i=1 to 8                                  ' select speed 2
  if not bp("d_s2"&i) then continue
  c(25+i)=1-c(25+i)
  if c(25+i) then sp$=.check$ else sp$=2^(i-1)
  button "d_s2"&i text sp$
  next i
if slider_changed("d_volmin") then             ' select minimum volume
  c(34)=floor(min(127*slider_value("d_volmin"),c(35)))
  slider "d_volmin" value c(34)/127
  end if
if slider_changed("d_volmax") then             ' select maximum volume
  c(35)=floor(max(127*slider_value("d_volmax"),c(34)))
  slider "d_volmax" value c(35)/127
  end if
if bp("d_mute") then                           ' select Mute button
  c(0)=1-c(0)
  if c(0) then
    button "d_mute" text "Mute" ! button "c10" text "Drums random"
    else
    button "d_mute" text "Muted" ! button "c10" text "(Drums random)"
    end if
  if not c(0) then d_back
  end if
if bp("d_close") then
  d_back:
  page_close ("drumwin")
  for i=0 to 35 ! .chan(10,i)=c(i) ! next i    ' save channel settings
  return
  end if
' if bp("debug") then debug pause              /*  debug  */
goto change
end def

def notes_gen$(ch)
dim c(36),not$(96)
a$=""
if .chan(ch,0)=0 then return a$               ' channel is muted
for i=0 to 35 ! c(i)=.chan(ch,i) ! next i     ' load channel settings
nlen=300 ! k=-1
for oc=1 to 8 ! if c(17+oc)=0 then continue   ' build notes string
  for no=0 to 11 ! if c(6+no)=0 then continue  ' for this channel
    k+=1 ! not$(k)=.notes$(no)&oc
    next no 
  next oc ! high=k ! nn=floor(high/2) ! a$=not$(nn)
if c(2)>=0 then a$&=" "&c(2)&":" else a$&=" "&(8*c(1)+rnd(8))&":"
for i=2 to nlen                               ' generate instrument
  if c(1)>=0 and rnd(1)<.05 then a$&=" "&(8*c(1)+rnd(8))&":"
  if rnd(1)<.5 then
    do ! k=rnd(8) ! until c(26+k)=1           ' generate speed
    a$&=mid$(.speed$,k,1)
    end if
  if rnd(1)<.1 then a$&="V"&(c(34)+rnd(c(35)-c(34)+1))  ' generate volume
  dn=rnd(9)-4                                           ' generate note
  nn+=dn ! nn=max(0,nn) ! nn=min(high,nn) ! a$&=not$(nn)
  next i
return a$
end def

def drum_gen$()
dim c(36)
a$=""
if .chan(10,0)=0 then return a$               ' channel is muted
if .chan(10,1)=-1 and .chan(10,2)=-1 then return a$   ' no drums
if .chan(10,35)=0 then return a$                      ' no volumes set
for i=0 to 35 ! c(i)=.chan(10,i) ! next i     ' load channel settings
if c(1)>=0 then d1$=.drum_not$(c(1)) else d1$=""
if c(2)>=0 then d2$=.drum_not$(c(2)) else d2$=""
nlen=300
d1_ok=0 ! d2_ok=0
for i=0 to 7 ! if c(18+i) then ! d1_ok=1 ! break ! end if ! next i
for i=0 to 7 ! if c(26+i) then ! d2_ok=1 ! break ! end if ! next i
if d1_ok=0 and d2_ok=0 then return a$         ' no speeds set
for i=2 to nlen
  if d1_ok then
    if rnd(1)<.3 then
      do ! k=rnd(8) ! until c(18+k)=1         ' generate speed drum1
      a$&=mid$(.speed$,k,1)
      end if
    a$&=d1$
    end if
  if d2_ok then
    if rnd(1)<.3 then
      do ! k=rnd(8) ! until c(26+k)=1         ' generate speed drum2
      a$&=mid$(.speed$,k,1)
      end if
    a$&=d2$
    end if
  if rnd(1)<.1 then a$&="V"&(c(34)+rnd(c(35)-c(34)+1))  ' generate volume
  next i
return a$
end def

def channel_window(xs,ys,ww,hh,R,G,B,alpha)
name$="channel" ! cn=channel.ch
page name$ set 
page name$ frame xs,ys,0,0
page name$ color R,G,B,alpha
button "close" title "❎" at ww-30,5 size 22,22
set buttons custom ! draw color 0,0,0
button "bottom" title "" at -6,hh-3 size ww+12,3
button "left" title "" at 0,-6 size 3,hh+12
button "right" title "" at ww-3,-6 size 3,hh+12
button "upper1" title "" at -6,0 size ww+12,3
button "upper2" title "" at -6,30 size ww+12,3
blue() ! grey()
button "title" title "" at (ww-190)/2,3 size 200,27
button "vol" title "Volume" at 20,150 size 160,30
button "vmin" title "Min." at 20,190 size 70,25
button "vmax" title "Max." at 110,190 size 70,25
button "notes" title "Notes" at 310,50 size 160,30
button "oct" title "Octaves" at 310,220 size 160,30
button "sp" title "Speed  (/sec)" at 310,330 size 160,30
fill color 1,1,0
button "gt" title "Groups table" at 20,50 size 160,30
button "it" title "Instrument table" at 20,100 size 160,30
slider "volmin" value .3 at 55,470 size 256 angle -90
slider "volmax" value .3 at 145,470 size 256 angle -90
for i=0 to 4
  but$="n"&.sec(i) ! x=245+floor((i+.1)/2.1)*50+50*i
  button but$ title .notes$(.sec(i)) at x,90 size 40,40
  next i
for i=0 to 6
  but$="n"&.prim(i)
  button but$ title .notes$(.prim(i)) at 220+50*i,150 size 40,40
  next i
for i=1 to 8
  but$="o"&i
  button but$ title i at 150+50*i,260 size 40,40
  next i
for i=1 to 8
  but$="s"&i
  button but$ title 2^(i-1) at 150+50*i,370 size 40,40
  next i
button "apl" title "Apply" at 200,440 size 70,40
button "def" title "Default" at 280,440 size 70,40
button "res" title "Reset" at 360,440 size 70,40
button "mute" title "Mute" at 440,440 size 70,40
button "fre" title "Free" at 520,440 size 70,40
black() ! grey()
page name$ hide
page name$ frame xs,ys,ww,hh
end def

def drum_window(xs,ys,ww,hh,R,G,B,alpha)
name$="drumwin" ! cn=10
page name$ set 
page name$ frame xs,ys,0,0
page name$ color R,G,B,alpha
button "d_close" title "❎" at ww-30,5 size 22,22
set buttons custom ! draw color 0,0,0
button "d_bottom" title "" at -6,hh-3 size ww+12,3
button "d_left" title "" at 0,-6 size 3,hh+12
button "d_right" title "" at ww-3,-6 size 3,hh+12
button "d_upper1" title "" at -6,0 size ww+12,3
button "d_upper2" title "" at -6,30 size ww+12,3
blue() ! grey()
button "d_title" title "Drums" at(ww-190)/2,3 size 200,27
button "d_vol" title "Volume" at 20,150 size 160,30
button "d_vmin" title "Min." at 20,190 size 70,25
button "d_vmax" title "Max." at 110,190 size 70,25
button "sp1" title "Speed drum1" at 310,50 size 160,30
button "sp2" title "Speed drum2" at 310,150 size 160,30
fill color 1,1,0
button "dr1" title "Drum instrument 1" at 10,50 size 170,30
button "dr2" title "Drum instrument 2" at 10,100 size 170,30
slider "d_volmin" value .3 at 55,470 size 256 angle -90
slider "d_volmax" value .3 at 145,470 size 256 angle -90
for i=1 to 8
  but$="d_s1"&i
  button but$ title 2^(i-1) at 150+50*i,90 size 40,40
  next i
for i=1 to 8
  but$="d_s2"&i
  button but$ title 2^(i-1) at 150+50*i,190 size 40,40
  next i
button "d_mute" title "Mute" at 510,440 size 80,40
black() ! grey()
page name$ hide
page name$ frame xs,ys,ww,hh
end def

def list_window(name$,titel$,cont$(),size,xs,ys,ww,hh,R,G,B,alpha)
dim temp$(size+1)
for i=0 to size ! temp$(i)=cont$(i) ! next i
page name$ set 
page name$ frame xs,ys,0,0
page name$ color R,G,B,alpha
' button name$&"_close" title "❎" at ww-30,5 size 22,22
button name$&"bottom" title "" at -6,hh-3 size ww+12,3
button name$&"left" title "" at 0,-6 size 3,hh+12
button name$&"right" title "" at ww-3,-6 size 3,hh+12
button name$&"upper1" title "" at -6,0 size ww+12,3
button name$&"upper2" title "" at -6,30 size ww+12,3
button name$&"title" title titel$ at 20,3 size ww-60,27
set lists custom
list name$ text temp$ at 2,32 size ww-4,hh-34
page name$ hide
page name$ frame xs,ys,ww,hh
end def

def page_open(pname$)
page pname$ alpha 0 ! page pname$ show
for a=8 to 0 step -1  ! pause .05 ! page pname$ alpha 1/(2^a) ! next a
end def

def page_close(pname$)
for a=1 to 0 step -.1 ! page pname$ alpha a ! pause .05 ! next a
page pname$ hide
end def

def grey() ! fill color .8,.8,.8 ! end def
def black() ! draw color 0,0,0 ! end def
def blue() ! draw color 0,0,1 ! end def
def bp(a$) = button_pressed(a$)


def app_init
randomize ! option angle degrees ! set underground on
graphics ! graphics clear ! black() ! grey()
restore
for i=0 to 15 ! read .group$(i) ! next i
for i=0 to 127 ! read .melody$(i) ! next i
for i=0 to 46 ! read .drum$(i) ! next i
for i=0 to 11 ! read .notes$(i) ! next i
for i=1 to 4 ! for j=0 to 35 ! read .chan(i,j) ! next j ! next i
for i=0 to 6 ! read .prim(i) ! next i
for i=0 to 4 ! read .sec(i) ! next i
data "Piano","Percussion","Organ","Guitar","Bass","Strings 1","Strings 2"
data "Brass","Reed","Pipe","Synth Lead","Synth Pad","Synth Effects"
data "Ethnic","Percussive","Sound effects"
data "Acoustic Grand Piano","Bright Acoustic Piano","Electric Grand Piano"
data "Honky-tonk Piano","Electric Piano 1","Electric Piano 2","Harpsichord"
data "Clavinet","Celesta","Glockenspiel","Music Box","Vibraphone","Marimba"
data "Xylophone","Tubular Bells","Dulcimer","Drawbar Organ"
data "Percussive Organ","Rock Organ","Church Organ","Reed Organ","Accordion"
data "Harmonica","Tango Accordion","Acoustic Guitar (nylon)"
data "Acoustic Guitar (steel)","Electric Guitar (jazz)"
data "Electric Guitar (clean)","Electric Guitar (muted)","Overdriven Guitar"
data "Distortion Guitar","Guitar harmonics","Acoustic Bass"
data "Electric Bass (finger)","Electric Bass (pick)","Fretless Bass"
data "Slap Bass 1","Slap Bass 2","Synth Bass 1","Synth Bass 2","Violin"
data "Viola","Cello","Contrabass","Tremolo Strings","Pizzicato Strings"
data "Orchestral Harp","Timpani","String Ensemble1","String Ensemble 2"
data "Synth Strings 1","Synth Strings 2","Choir Aahs","Voice Oohs"
data "Synth Voice","Orchestra Hit","Trumpet","Trombone","Tuba"
data "Muted Trumpet","French Horn","Brass Section","Synth Brass 1"
data "Synth Brass 2","Soprano Sax","Alto Sax","Tenor Sax","Baritone Sax"
data "Oboe","English Horn","Bassoon","Clarinet","Piccolo","Flute","Recorder"
data "Pan Flute","Blown Bottle","Shakuhachi","Whistle","Ocarina"
data "Lead 1 (square)","Lead 2 (sawtooth)","Lead 3 (calliope)"
data "Lead 4 (chiff)","Lead 5 (charang)","Lead 6 (voice)","Lead 7 (fifths)"
data "Lead 8 (bass + lead)","Pad 1 (new age)","Pad 2 (warm)"
data "Pad 3 (polysynth)","Pad 4 (choir)","Pad 5 (bowed)","Pad 6 (metallic)"
data "Pad 7 (halo)","Pad 8 (sweep)","FX 1 (rain)","FX 2 (soundtrack)"
data "FX 3 (crystal)","FX 4 (atmosphere)","FX 5 (brightness)"
data "FX 6 (goblins)","FX 7 (echoes)","FX 8 (sci-fi)","Sitar","Banjo"
data "Shamisen","Kot","Kalimba","Bag pipe","Fiddle","Shanai","Tinkle Bell"
data "Agogo","Steel Drums","Woodblock","Taiko Drum","Melodic Tom"
data "Synth Drum","Reverse Cymbal","Guitar Fret Noise","Breath Noise"
data "Seashore","Bird Tweet","Telephone Ring","Helicopter","Applause"
data "Gunshot"
data "Bass Drum","Kick Drum","Snare Cross Stick","Snare Drum","Hand Clap"
data "Electric Snare Drum","Floor Tom 2","Hi-Hat Closed","Floor Tom 1"
data "Hi-Hat Foot","Low Tom","Hi-Hat Open","Low-Mid Tom","High-Mid Tom"
data "Crash Cymbal","High Tom","Ride Cymbal","China Cymbal","Ride Bell"
data "Tambourine","Splash cymbal","Cowbell","Crash Cymbal 2","Vibraslap"
data "Ride Cymbal 2","High Bongo","Low Bongo","Conga Dead Stroke","Conga"
data "Tumba","High Timbale","Low Timbale","High Agogo","Low Agogo","Cabasa"
data "Maracas","Whistle Short","Whistle Long","Guiro Short","Guiro Long"
data "Claves","High Woodblock","Low Woodblock","Cuica High","Cuica Low"
data "Triangle Mute","Triangle Open"
data "c","c#","d","d#","e","f","f#","g","g#","a","a#","b"
data 1 ,-1 ,0,0,0,0, 1 ,0,0,0, 1 ,0,0, 1 ,0, 1 ,0,0,0, 1 , 1
data 1 , 1 ,0,0,0,0,1 , 1 ,0, 1 ,0,0,0, 61 , 83
data 1 ,-1 , 36 ,0,0,0, 1 ,0,0,0, 1 ,0,0, 1 ,0,0,0, 1 ,0, 1 , 1 ,0,0
data 0,0,0,0,0,0, 1 , 1 ,0,0,0, 47 , 89
data 1 , 7 ,-1 ,0,0,0, 1 ,0, 1 ,0, 1 , 1 ,0, 1 ,0, 1 ,0, 1 ,0,0, 1 , 1
data 1 ,0,0,0,0,0, 1 , 1 , 1 ,0,0,0, 43 , 59
data 1 , 1 ,-1 ,0,0,0, 1 ,0,0,0, 1 , 1 ,0,0,0, 1 ,0,0,0,0, 1 , 1
data 0,0,0,0,0,0, 1 , 1 , 1 ,0,0,0, 51 , 73
data 0,2,4,5,7,9,11,  1,3,6,8,10
k=-1 ! i=10 ! oct=1
do ! k+=1 ! i+=1 ! .drum_not$(k)=.notes$(i)&oct
  if i=11 then ! i=-1 ! oct+=1 ! end if
  until k=46
for i=0 to 35 ! read .chan(0,i) ! next i
data 1,-1,0,0,0,0, 1,0,0,0,1,0,0,0,0,1,0,0, 0,0,1,1,1,1,0,0, 0,0,1,1,0,1,0,0, 48,99
.speed$="WHQISTXY" ! .nots$="cdefgab" ! .check$="✅"
for i=5 to 10 ! .chan(i,1)=-1 ! .chan(i,2)=-1 ! next i
set buttons custom
draw font size 24
blue() ! draw text "Channels" at 50,15
for ch=1 to 9
  but$="c"&ch
  if .chan(ch,1)=-1 and .chan(ch,2)=-1 then
    titel$="Free"
    else
    if .chan(ch,1)>=0 then
      titel$=.group$(.chan(ch,1))
      else ! titel$=.melody$(.chan(ch,2))
      end if
    end if
  button but$ title titel$ at 20,70*ch-10 size 200,40
  next ch
button "c10" title "(Drums random)" at 20,720 size 200,40
button "c11" title "(Drum machine)" at 20,790 size 200,40
' button "debug" title "Debug" at 20,900 size 200,40
black()
channel_window(140,180,610,500,.8,.8,.8,1)
drum_window(140,180,610,500,.8,.8,.8,1)
list_window("group"," Groups",.group$,15,450,130,220,750,.8,.8,.8,1)
list_window("melody"," Melody",.melody$,127,450,130,220,750,.8,.8,.8,1)
list_window("drums","Drums",.drum$,46,450,130,220,750,.8,.8,.8,1)
end def