Advertisement
Guest User

memusic

a guest
Jan 21st, 2020
91
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Lua 34.87 KB | None | 0 0
  1. local defaultPatternLength = 32
  2. local defaultMeasure = 4
  3. local songBpm = 240
  4. local songLength = 1
  5.  
  6. local sp = {}
  7. local _i = 0
  8. for i=0, 50 do
  9.     local p = peripheral.wrap("speaker_"..i)
  10.     if (p ~= nil) then
  11.         sp[_i] = p
  12.         _i = _i+1
  13.     end
  14. end
  15.  
  16. local nextSpeaker = 0
  17. local speakerCount = table.getn(sp)
  18.  
  19. local instrumentCount = 11
  20. local instruments = {
  21.     -- musical
  22.     {["name"] = "piano", ["file"] = "block.note.harp"},
  23.     {["name"] = "bass", ["file"] = "block.note.bass"},
  24.     {["name"] = "bell", ["file"] = "block.note.bell"},
  25.     {["name"] = "chime", ["file"] = "block.note.chime"},
  26.     {["name"] = "xhylophone", ["file"] = "block.note.xylophone"},
  27.     {["name"] = "flute", ["file"] = "block.note.flute"},
  28.     {["name"] = "guitar", ["file"] = "block.note.guitar"},
  29.     {["name"] = "kick", ["file"] = "block.note.basedrum"},
  30.     {["name"] = "hat", ["file"] = "block.note.hat"},
  31.     {["name"] = "cimbal", ["file"] = "block.sand.break"},
  32.     {["name"] = "snare", ["file"] = "block.note.snare"},
  33.     -- sfx
  34.     {["name"] = "levelup", ["file"] ="entity.player.levelup"}
  35. }
  36.  
  37. local notes = {
  38.     "F#", "G ", "G#", "A ", "A#", "B ",
  39.     "C ", "C#", "D ", "D#", "E ", "F "
  40. }
  41.  
  42. local song = {}
  43. local patterns = {}
  44.  
  45. local currentPattern = 1
  46. local currentSongPattern = 1
  47. local currentChannel = 1
  48. local currentYOffset = 0
  49. local currentXOffset = 0
  50. local cursor = 1
  51. local playing = false
  52. local pressingShift = false
  53.  
  54. local playingTimer = nil
  55. local delayedNoteTimer = nil
  56. local delayedAllChannels = false
  57. local delayTime = 1
  58.  
  59. local menuSongPatternScroll = 1
  60. local menuChannelScroll = 1
  61.  
  62. local beatsOnScreen = 30
  63. local scrW, scrH = term.getSize()
  64.  
  65. -- Data of the current pattern
  66. local function getCurrentNotes(time)
  67.     local notes = patterns[currentPattern].channels[currentChannel].notes[time]
  68.     if (notes == nil) then
  69.         return ""
  70.     else
  71.         return notes
  72.     end
  73. end
  74.  
  75. -- Data of the pattern for the specified channel
  76. local function getChannelNotes(channel, time)
  77.     local notes = patterns[currentPattern].channels[channel].notes[time]
  78.     if (notes == nil) then
  79.         return ""
  80.     else
  81.         return notes
  82.     end
  83. end
  84.  
  85. -- Get an instrument by name
  86. local function getInstrumentByName(name)
  87.     for k, v in pairs(instruments) do
  88.         if (v.name == name) then
  89.             return v
  90.         end
  91.     end
  92.     error("Invalid instrument name")
  93. end
  94.  
  95. -- Get an instrument ID by name
  96. local function getInstrumentIDByName(name)
  97.     for i=1, instrumentCount do
  98.         if (instruments[i].name == name) then
  99.             return i
  100.         end
  101.     end
  102.     error("Invalid instrument name")
  103. end
  104.  
  105. -- Note character to note number
  106. local function characterToNote(c)
  107.     local delayed = true
  108.     if (string.byte(c) >= 97) then
  109.         delayed = false
  110.     end
  111.    
  112.     if (delayed) then
  113.         return string.byte(c)-65, delayed
  114.     else
  115.         return string.byte(c)-97, delayed
  116.     end
  117. end
  118.  
  119. -- Note number to note character
  120. local function noteToCharacter(n, delayed)
  121.     if (delayed) then
  122.         return string.char(tonumber(n)+65) --Mayuscula
  123.     else
  124.         return string.char(tonumber(n)+97) --minuscula
  125.     end
  126. end
  127.  
  128. -- Pitch of a note number
  129. local function notePitch(n)
  130.     return math.pow(2, (n-12)/12)
  131. end
  132.  
  133. -- Pitch of a note character
  134. local function charPitch(c)
  135.     return notePitch(characterToNote(c))
  136. end
  137.  
  138. local function playSoundEffect(soundname, vol, pitch)
  139.     sp[nextSpeaker].playSound(getInstrumentByName(soundname).file, vol, pitch)
  140.     nextSpeaker = nextSpeaker+1
  141.     if (nextSpeaker > speakerCount) then
  142.         nextSpeaker = 0
  143.     end
  144. end
  145.  
  146. -- Play a single note number
  147. local function playNote(inst, vol, note)
  148.     sp[nextSpeaker].playSound(instruments[inst].file, vol, note)
  149.     nextSpeaker = nextSpeaker+1
  150.     if (nextSpeaker > speakerCount) then
  151.         nextSpeaker = 0
  152.     end
  153. end
  154.  
  155. -- Play a string of notes
  156. local function playBar(inst, vol, notes, delayed)
  157.     for n=1, string.len(notes) do
  158.         local note = string.sub(notes, n, n)
  159.         if (delayed and string.byte(note) < 97) then -- If its delayed, play only uppercases
  160.             playNote(inst, vol, charPitch(note))
  161.         elseif (not delayed and string.byte(note) >= 97) then -- If not, play only lowercases
  162.             playNote(inst, vol, charPitch(note))
  163.         end
  164.     end
  165. end
  166.  
  167. -- Play the delayed bar
  168. local function playCurrentBarDelayed()
  169.     if (delayedAllChannels) then
  170.         for i=1, instrumentCount do
  171.             playBar(i, 1, getChannelNotes(i, delayTime), true)
  172.         end
  173.     else
  174.         playBar(currentChannel, 1, getCurrentNotes(delayTime), true)
  175.     end
  176. end
  177.  
  178. -- Play the bar at a specified time
  179. local function playSpecificBar(time, allChannels)
  180.     delayTime = time
  181.     if (allChannels) then
  182.         for i=1, instrumentCount do
  183.             playBar(i, 1, getChannelNotes(i, time), false)
  184.         end
  185.     else
  186.         playBar(currentChannel, 1, getCurrentNotes(time), false)
  187.     end
  188.     delayedNoteTimer = os.startTimer(30/(songBpm*patterns[currentPattern].speed)-0.001)
  189.     delayedAllChannels = allChannels
  190. end
  191.  
  192. -- Play the current channel's bar currently indicated by the cursor
  193. local function playCurrentChannelBar()
  194.     playSpecificBar(cursor, false)
  195. end
  196.  
  197. -- Play the every bar currently indicated by the cursor
  198. local function playCurrentBar()
  199.     playSpecificBar(cursor, true)
  200. end
  201.  
  202. -- Add a character to the middle of a string
  203. local function addCharAt(str, char, pos)
  204.     local prev = string.sub(str, 1, pos)
  205.     local post = string.sub(str, pos+1, string.len(str))
  206.     return prev..char..post
  207. end
  208.  
  209. -- Remove a character from a string
  210. local function removeCharacterAt(str, pos)
  211.     local prev = string.sub(str, 1, pos-1)
  212.     local post = string.sub(str, pos+1, string.len(str))
  213.     return prev..post
  214. end
  215.  
  216. -- Replace a character in the middle of a string
  217. local function replaceCharAt(str, char, pos)
  218.     local prev = string.sub(str, 1, pos)
  219.     local post = string.sub(str, pos+2, string.len(str))
  220.     return prev..char..post
  221. end
  222.  
  223. -- Pixel coordinates to time and note character
  224. local function pixelToMusic(x, y, delayed)
  225.     local time = x-3+currentXOffset
  226.     local note = noteToCharacter(scrH-y+currentYOffset, delayed)
  227.     return time, note
  228. end
  229.  
  230. -- Time and note character to pixel coordinates
  231. local function musicToPixel(time, char)
  232.     local noteNumber, delayed = characterToNote(char)
  233.     local x = time+3-currentXOffset
  234.     local y = -noteNumber+currentYOffset+scrH
  235.     return x, y
  236. end
  237.  
  238. -- StartPlaying
  239. local function playFromCursor()
  240.     playing = true
  241.     playingTimer = os.startTimer(60/(songBpm*patterns[currentPattern].speed))
  242.     playCurrentBar()
  243. end
  244.  
  245. -- StartPlaying
  246. local function playFromStart()
  247.     cursor = 1
  248.     currentXOffset = 0
  249.     playing = true
  250.     playingTimer = os.startTimer(60/(songBpm*patterns[currentPattern].speed))
  251.     playCurrentBar()
  252. end
  253.  
  254. -- Pause
  255. local function stop()
  256.     playing = false
  257.     cursor = 1
  258. end
  259.  
  260. -- Pause
  261. local function pause()
  262.     playing = false
  263. end
  264.  
  265. -- Draw the musical sheet section of the screen
  266. local function DrawPattern()
  267.     local channel = currentChannel
  268.     local pattern = currentPattern
  269.     local xoffset = currentXOffset
  270.     local yoffset = currentYOffset
  271.  
  272.     if (patterns[pattern] == nil) then return end
  273.  
  274.     local measure = patterns[pattern].measure
  275.     local patternLength = patterns[pattern].length
  276.  
  277.     for _y=1, scrH-2 do
  278.         local y = scrH-_y
  279.         local octave = math.floor((_y+yoffset-7)/12)+1
  280.         local n = (_y+yoffset)%12
  281.         local c = xoffset
  282.         term.setCursorPos(1,y+1)
  283.        
  284.         term.setBackgroundColor(colors.black)
  285.         if (n==1 or n==3 or n==5 or n==8 or n==10) then
  286.             term.setTextColor(colors.blue)
  287.         else
  288.             term.setTextColor(colors.cyan)
  289.         end
  290.         term.write(notes[(n-1)%12+1]..tostring(octave))
  291.        
  292.         local lineBackgroundColor = colors.white
  293.         local lineTextColor = colors.lightGray
  294.         local blackNote = false
  295.         if (n==1 or n==3 or n==5 or n==8 or n==10) then
  296.             lineBackgroundColor = colors.lightGray
  297.             lineTextColor = colors.gray
  298.             blackNote = true
  299.         end
  300.  
  301.         local patternLength = patterns[pattern].length
  302.         for c=xoffset, math.min(patternLength-1, xoffset+beatsOnScreen-1) do
  303.             term.setBackgroundColor(lineBackgroundColor)
  304.             term.setTextColor(lineTextColor)
  305.  
  306.             -- Draw Cursor Bar
  307.             if (cursor == c+1) then
  308.                 if (playing) then
  309.                     term.setBackgroundColor(colors.red)
  310.                     term.setTextColor(colors.black)
  311.                 else
  312.                     term.setBackgroundColor(colors.yellow)
  313.                     if (blackNote) then
  314.                         term.setTextColor(colors.brown)
  315.                     else
  316.                         term.setTextColor(colors.orange)
  317.                     end
  318.                 end
  319.             end
  320.  
  321.             if (c%(measure*4) == 0) then
  322.                 term.write("|")
  323.             elseif (c%measure == 0) then
  324.                 term.write(",")
  325.             else
  326.                 term.write("_")
  327.             end
  328.         end
  329.     end
  330.     term.setCursorPos(1,1)
  331.     term.setBackgroundColor(colors.black)
  332.     term.setTextColor(colors.yellow)
  333.     term.write(string.rep(" ", measure+3))
  334.     local i = 1+(-xoffset)%measure
  335.     local firstBeat = math.floor((xoffset-1)/measure)+1
  336.     for c=firstBeat, math.min(firstBeat+beatsOnScreen/measure-1, patternLength/measure-1) do
  337.         term.setCursorPos(3+i, 2)
  338.         term.write(tonumber(c+1))
  339.         term.write(string.rep(" ", measure))
  340.         i = i+measure
  341.     end
  342.    
  343.     -- Draw other instruments notes
  344.     for ch=1, instrumentCount do
  345.         if (ch ~= currentChannel) then
  346.             for time=xoffset+1, math.min(xoffset+beatsOnScreen, patternLength) do
  347.                 local notes = getChannelNotes(ch, time)
  348.                 local paintedNotes = {}
  349.                 for n=1, string.len(notes) do
  350.                     local noteCharacter = string.sub(notes, n, n)
  351.                     local delayed = true
  352.                     if (string.byte(noteCharacter) >= 97) then
  353.                         delayed = false
  354.                     end
  355.                     local x, y = musicToPixel(time, noteCharacter)
  356.                     term.setTextColor(colors.lightGray)
  357.                     if (y > 2) then
  358.                         if (paintedNotes[y]) then
  359.                             term.setBackgroundColor(colors.pink)
  360.                             term.setCursorPos(x, y)
  361.                             term.write("x")
  362.                         else
  363.                             if (delayed) then
  364.                                 term.setBackgroundColor(colors.pink)
  365.                                 term.setCursorPos(x, y)
  366.                                 term.write(">")
  367.                                 paintedNotes[y] = true
  368.                             else
  369.                                 term.setBackgroundColor(colors.lightBlue)
  370.                                 term.setCursorPos(x, y)
  371.                                 term.write(" ")
  372.                                 paintedNotes[y] = true
  373.                             end
  374.                         end
  375.                     end
  376.                 end
  377.             end
  378.         end
  379.     end
  380.  
  381.     -- Draw current instruments notes
  382.     for time=xoffset+1, math.min(xoffset+beatsOnScreen, patternLength) do
  383.         local notes = getCurrentNotes(time)
  384.         local paintedNotes = {}
  385.         for n=1, string.len(notes) do
  386.             local noteCharacter = string.sub(notes, n, n)
  387.             local delayed = true
  388.             if (string.byte(noteCharacter) >= 97) then
  389.                 delayed = false
  390.             end
  391.             local x, y = musicToPixel(time, noteCharacter)
  392.             term.setTextColor(colors.black)
  393.             if (y > 2) then
  394.                 if (paintedNotes[y]) then
  395.                     term.setBackgroundColor(colors.purple)
  396.                     term.setCursorPos(x, y)
  397.                     term.write("x")
  398.                 else
  399.                     if (delayed) then
  400.                         term.setBackgroundColor(colors.red)
  401.                         term.setCursorPos(x, y)
  402.                         term.write(">")
  403.                         paintedNotes[y] = true
  404.                     else
  405.                         term.setBackgroundColor(colors.blue)
  406.                         term.setCursorPos(x, y)
  407.                         term.write(" ")
  408.                         paintedNotes[y] = true
  409.                     end
  410.                 end
  411.             end
  412.         end
  413.     end
  414.  
  415.     term.setBackgroundColor(colors.pink)
  416.     term.setTextColor(colors.black)
  417.     term.setCursorPos(1,1)
  418.     term.write(" Parte "..tostring(song.patterns[currentSongPattern]).." ")
  419.  
  420.     term.setBackgroundColor(colors.black)
  421.     term.write(" ")
  422.  
  423.     term.setBackgroundColor(colors.lime)
  424.     term.write(" "..instruments[currentChannel].name.." ")
  425. end
  426.  
  427. -- Draw the control panel
  428. local function DrawPanel()
  429.     local panelWidth = scrW-(beatsOnScreen+3)
  430.     local x = scrW-panelWidth+1
  431.     term.setBackgroundColor(colors.brown)
  432.     for y=1, scrH do
  433.         term.setCursorPos(x,y)
  434.         term.write(string.rep(" ", panelWidth))
  435.     end
  436.  
  437.     term.setBackgroundColor(colors.orange)
  438.     term.setTextColor(colors.black)
  439.  
  440.     -- Menues
  441.     term.setCursorPos(x+1, 1)
  442.     term.write("Gua")
  443.  
  444.     term.setCursorPos(x+5, 1)
  445.     term.write("Car")
  446.  
  447.     term.setBackgroundColor(colors.brown)
  448.     term.setTextColor(colors.orange)
  449.     term.setCursorPos(x+9, 1)
  450.     term.write("Bpm: ")
  451.     term.setBackgroundColor(colors.orange)
  452.     term.setTextColor(colors.black)
  453.     term.write(songBpm)
  454.  
  455.     -- Patterns
  456.     term.setTextColor(colors.black)
  457.     if (menuSongPatternScroll == 1) then
  458.         term.setBackgroundColor(colors.gray)
  459.     else
  460.         term.setBackgroundColor(colors.lightGray)
  461.     end
  462.     term.setCursorPos(x+1, 3)
  463.     term.write("   ^   ")
  464.  
  465.     local sp = menuSongPatternScroll
  466.     for y= 4, 8 do
  467.         if (sp == currentSongPattern) then
  468.                 term.setBackgroundColor(colors.pink)
  469.         else
  470.             term.setBackgroundColor(colors.black)
  471.         end
  472.         term.setCursorPos(x+1, y)
  473.         term.write("       ")
  474.  
  475.         if (sp <= songLength) then
  476.             if (sp == currentSongPattern) then
  477.                 term.setBackgroundColor(colors.pink)
  478.                 term.setTextColor(colors.black)
  479.             else
  480.                 term.setBackgroundColor(colors.black)
  481.                 term.setTextColor(colors.pink)
  482.             end
  483.  
  484.             term.setCursorPos(x+1, y)
  485.             term.write("#"..sp)
  486.  
  487.             term.setCursorPos(x+5, y)
  488.             term.write("P"..song.patterns[sp])
  489.  
  490.             sp = sp+1
  491.         end
  492.     end
  493.  
  494.     term.setTextColor(colors.black)
  495.     if (menuSongPatternScroll >= songLength-4) then
  496.         term.setBackgroundColor(colors.gray)
  497.     else
  498.         term.setBackgroundColor(colors.lightGray)
  499.     end
  500.     term.setCursorPos(x+1, 9)
  501.     term.write("   v   ")
  502.  
  503.      -- Instruments
  504.     term.setTextColor(colors.black)
  505.     if (menuChannelScroll == 1) then
  506.         term.setBackgroundColor(colors.gray)
  507.     else
  508.         term.setBackgroundColor(colors.lightGray)
  509.     end
  510.     term.setCursorPos(x+10, 3)
  511.     term.write("   ^   ")
  512.  
  513.     local ch = menuChannelScroll
  514.     local y = 4
  515.     for y= 4, 8 do
  516.         if (ch == currentChannel) then
  517.             term.setBackgroundColor(colors.lime)
  518.         else
  519.             term.setBackgroundColor(colors.black)
  520.         end
  521.         term.setCursorPos(x+10, y)
  522.         term.write("       ")
  523.  
  524.         term.setCursorPos(x+10, y)
  525.         if (ch == currentChannel) then
  526.             term.setBackgroundColor(colors.lime)
  527.             term.setTextColor(colors.black)
  528.         else
  529.             term.setBackgroundColor(colors.black)
  530.             term.setTextColor(colors.lime)
  531.         end
  532.  
  533.         term.write(string.sub(instruments[ch].name, 1, 7))
  534.         ch = ch+1
  535.     end
  536.  
  537.     term.setTextColor(colors.black)
  538.     if (menuChannelScroll >= instrumentCount-4) then
  539.         term.setBackgroundColor(colors.gray)
  540.     else
  541.         term.setBackgroundColor(colors.lightGray)
  542.     end
  543.     term.setCursorPos(x+10, 9)
  544.     term.write("   v   ")
  545.  
  546.     term.setTextColor(colors.black)
  547.  
  548.  
  549.     -- Pattern Options
  550.     term.setTextColor(colors.black)
  551.  
  552.     term.setCursorPos(x+1, 10)
  553.     term.setBackgroundColor(colors.purple)
  554.     term.write("repetir")
  555.  
  556.     term.setCursorPos(x+1, 11)
  557.     term.setBackgroundColor(colors.pink)
  558.     term.write(" nueva ")
  559.  
  560.     term.setCursorPos(x+10, 11)
  561.     term.setBackgroundColor(colors.pink)
  562.     term.write("dupliC.")
  563.  
  564.     term.setCursorPos(x+1, 12)
  565.     term.setBackgroundColor(colors.purple)
  566.     term.write("mover ^")
  567.  
  568.     term.setCursorPos(x+10, 12)
  569.     term.setBackgroundColor(colors.purple)
  570.     term.write("  P +1 ")
  571.  
  572.     term.setCursorPos(x+1, 13)
  573.     term.setBackgroundColor(colors.pink)
  574.     term.write("mover v")
  575.  
  576.     term.setCursorPos(x+10, 13)
  577.     term.setBackgroundColor(colors.pink)
  578.     term.write("  P -1 ")
  579.  
  580.    
  581.     -- Settings
  582.     term.setCursorPos(x+1, 14)
  583.     term.setBackgroundColor(colors.brown)
  584.     term.setTextColor(colors.pink)
  585.     term.write("Velocidad: ")
  586.     term.setBackgroundColor(colors.purple)
  587.     term.setTextColor(colors.black)
  588.     term.write(" "..patterns[currentPattern].speed.." ")
  589.  
  590.     term.setCursorPos(x+1, 15)
  591.     term.setBackgroundColor(colors.brown)
  592.     term.setTextColor(colors.pink)
  593.     term.write("Largo: ")
  594.     term.setBackgroundColor(colors.pink)
  595.     term.setTextColor(colors.black)
  596.     term.write(" "..patterns[currentPattern].length.." ")
  597.  
  598.     term.setCursorPos(x+1, 16)
  599.     term.setBackgroundColor(colors.brown)
  600.     term.setTextColor(colors.pink)
  601.     term.write("Medida:")
  602.     term.setBackgroundColor(colors.purple)
  603.     term.setTextColor(colors.black)
  604.     term.write(" "..patterns[currentPattern].measure.." ")
  605.  
  606.  
  607.     -- More Options
  608.     term.setCursorPos(x+1, 18)
  609.     term.setBackgroundColor(colors.lime)
  610.     term.write("limpiar Instrum.")
  611.  
  612.     term.setCursorPos(x+1, 19)
  613.     term.setBackgroundColor(colors.pink)
  614.     term.write("borrar Parte")
  615.  
  616. end
  617.  
  618. -- Draw the entire screen
  619. local function DrawScreen()
  620.     term.setBackgroundColor(colors.black)
  621.     term.clear()
  622.     term.setTextColor(colors.white)
  623.     DrawPattern()
  624.     DrawPanel()
  625. end
  626.  
  627. -- GUI Functions
  628. -- Scroll sheet
  629. local function scrollRight() if (currentXOffset < patterns[currentPattern].length-beatsOnScreen) then currentXOffset = currentXOffset+1
  630. DrawScreen() end end
  631. local function scrollLeft() if (currentXOffset > 0) then currentXOffset = currentXOffset-1
  632. DrawScreen() end end
  633. local function scrollUp() if (currentYOffset < 27-scrH) then currentYOffset = currentYOffset+1
  634. DrawScreen() end end
  635. local function scrollDown() if (currentYOffset > 0) then currentYOffset = currentYOffset-1
  636. DrawScreen() end end
  637. -- Scroll song patterns
  638. local function nextSongPattern() if (menuSongPatternScroll < songLength-4) then menuSongPatternScroll = menuSongPatternScroll+1
  639. DrawPanel() end end
  640. local function prevSongPattern() if (menuSongPatternScroll > 1) then menuSongPatternScroll = menuSongPatternScroll-1
  641. DrawPanel() end end
  642. -- Scroll instruments
  643. local function nextChannel() if (menuChannelScroll < instrumentCount-4) then menuChannelScroll = menuChannelScroll+1
  644. DrawPanel() end end
  645. local function prevChannel() if (menuChannelScroll > 1) then menuChannelScroll = menuChannelScroll-1
  646. DrawPanel() end end
  647.  
  648. local function newPattern()
  649.     local p = {
  650.         ["channels"] = {},
  651.         ["length"] = defaultPatternLength,
  652.         ["speed"] = 1,
  653.         ["measure"] = defaultMeasure
  654.     }
  655.     for i=1, instrumentCount do
  656.         p.channels[i] = {
  657.             ["notes"] = {}
  658.         }
  659.     end
  660.     return p
  661. end
  662.  
  663. local function newSong()
  664.     song = {
  665.         ["patterns"] = {}
  666.     }
  667.     currentPattern = 1
  668.     patterns[currentPattern] = newPattern()
  669. end
  670.  
  671. -- Save song to a disk
  672. local function saveSong()
  673.     if (disk.isPresent("bottom")) then
  674.         term.setBackgroundColor(colors.brown)
  675.         term.clear()
  676.         term.setTextColor(colors.white)
  677.         term.setCursorPos(10,5)
  678.         term.write("Nombre de la canción: ")
  679.         term.setBackgroundColor(colors.white)
  680.         term.setTextColor(colors.black)
  681.         term.setCursorPos(10,6)
  682.         term.write(string.rep(" ", 15))
  683.         term.setCursorPos(10,6)
  684.         local title = read()
  685.         disk.setLabel("bottom", title)
  686.  
  687.         local f = fs.open("disk/memsong.txt", "w")
  688.         f.writeLine("title")
  689.         f.writeLine(title)
  690.         f.writeLine("bpm")
  691.         f.writeLine(math.floor(songBpm))
  692.         f.writeLine("structure")
  693.         for i=1, songLength do
  694.             f.writeLine(song.patterns[i])
  695.         end
  696.         f.writeLine("")
  697.         for k, v in pairs(patterns) do
  698.             f.writeLine("pattern")
  699.             f.writeLine(k)
  700.             f.writeLine("length")
  701.             f.writeLine(v.length)
  702.             f.writeLine("speed")
  703.             f.writeLine(v.speed)
  704.             f.writeLine("measure")
  705.             f.writeLine(v.measure)
  706.             f.writeLine("notes")
  707.             for chkey, ch in pairs(v.channels) do
  708.                 local notesString = ""
  709.                 local spaces = 0
  710.                 for i=1, v.length do
  711.                     if (ch.notes[i] ~= nil and ch.notes[i] ~= "") then
  712.                         if (spaces > 0) then
  713.                             notesString = notesString..spaces..ch.notes[i]
  714.                         else
  715.                             notesString = notesString..ch.notes[i]
  716.                         end
  717.                         spaces = 0
  718.                     end
  719.                     spaces = spaces+1
  720.                 end
  721.                 if (notesString ~= "") then
  722.                     f.writeLine(instruments[chkey].name)
  723.                     f.writeLine(notesString)
  724.                 end
  725.             end
  726.             f.writeLine("")
  727.         end
  728.         f.close()
  729.     end
  730. end
  731.  
  732. -- Load song from disk
  733. local function loadSong()
  734.  term.setBackgroundColor(colors.black)
  735.  term.clear()
  736.  term.setCursorPos(1,1)
  737.  term.setTextColor(colors.orange)
  738.     print("Loading...")
  739.     sleep(0.1)
  740.     local f = fs.open("disk/memsong.txt", "r")
  741.  
  742.     local fileTitle = "unknown"
  743.     local fileBpm = 240
  744.     local fileSong = {}
  745.  
  746.     newSong()
  747.     patterns = {}
  748.  
  749.     local line = f.readLine()
  750.     repeat
  751.         if (line == "title") then
  752.             fileTitle = f.readLine()
  753.         elseif (line == "bpm") then
  754.             fileBpm = tonumber(f.readLine())
  755.         elseif (line == "structure") then
  756.             local songPart = f.readLine()
  757.             local i=1
  758.             repeat
  759.                 fileSong[i] = tonumber(songPart)
  760.                 i = i+1
  761.                 songPart = f.readLine()
  762.             until songPart == ""
  763.         elseif (line == "pattern") then
  764.             local currentPattern = tonumber(f.readLine())
  765.             if (currentPattern ~= nil) then
  766.                 patterns[currentPattern] = newPattern()
  767.                 local pLine = f.readLine()
  768.                 repeat
  769.                     local broken = false
  770.                     if (pLine == "length") then
  771.                         patterns[currentPattern].length = tonumber(f.readLine())
  772.                     elseif (pLine == "measure") then
  773.                         patterns[currentPattern].measure = tonumber(f.readLine())
  774.                     elseif (pLine == "speed") then
  775.                         patterns[currentPattern].speed = tonumber(f.readLine())
  776.                     elseif (pLine == "notes") then
  777.                         local instrument = f.readLine()
  778.                         if (instrument ~= "") then
  779.                             repeat
  780.                                 local noteString = f.readLine()
  781.                                 local notes = {}
  782.                                 local pointer = 1
  783.                                 local spaces = 0
  784.  
  785.                                 for i=1, string.len(noteString) do
  786.                                    
  787.                                     local char = string.sub(noteString, i, i)
  788.  
  789.                                     if (tonumber(char)) then -- If the character is a number, count spaces
  790.                                         spaces = spaces*10
  791.                                         spaces = spaces+tonumber(char)
  792.                                     else
  793.                                         pointer = pointer+spaces
  794.                                         if (notes[pointer] == nil) then
  795.                                             notes[pointer] = ""
  796.                                         end
  797.                                         notes[pointer] = notes[pointer]..char
  798.                                         spaces = 0
  799.                                     end
  800.                                 end
  801.  
  802.                                 print("P"..currentPattern.." - "..instrument)
  803.                                 sleep(0.02)
  804.         patterns[currentPattern].channels[getInstrumentIDByName(instrument)].notes = notes
  805.  
  806.                                 instrument = f.readLine()
  807.                             until instrument == ""
  808.                             broken = true
  809.                         end
  810.                     end
  811.                     if (broken) then
  812.                         pLine = nil
  813.                     else
  814.                         pLine = f.readLine()
  815.                     end
  816.                 until pLine == "" or pLine == nil
  817.             end
  818.         end
  819.         line = f.readLine()
  820.     until line == "" or line == nil
  821.  print("done")
  822.     sleep(0.2)
  823.     f.close()
  824.  
  825.     song.patterns = fileSong
  826.     songLength = #song.patterns
  827.     songBpm = fileBpm
  828.     currentSongPattern = 1
  829.     currentPattern = song.patterns[1]
  830. end
  831.  
  832. -- Pattern manipulation
  833. local function getFirstFreePattern()
  834.     local i = 1
  835.     while patterns[i] ~= nil do
  836.         i = i+1
  837.     end
  838.     return i
  839. end
  840.  
  841. -- Clear instrument
  842. local function clearInstrument()
  843.     patterns[currentPattern].notes = {}
  844. end
  845.  
  846. -- New pattern
  847. local function repeatPattern()
  848.     songLength = songLength+1
  849.     for i=songLength, currentSongPattern, -1 do
  850.         song.patterns[i+1] = song.patterns[i]
  851.     end
  852.     currentSongPattern = currentSongPattern+1
  853. end
  854.  
  855. -- New pattern
  856. local function addPattern()
  857.     currentPattern = getFirstFreePattern()
  858.     patterns[currentPattern] = newPattern()
  859.     songLength = songLength+1
  860.     currentSongPattern = songLength
  861.     song.patterns[currentSongPattern] = currentPattern
  862. end
  863.  
  864. -- Duplicate pattern
  865. local function duplicatePattern()
  866.     local oldPattern = currentPattern
  867.     songLength = songLength+1
  868.     currentPattern = getFirstFreePattern()
  869.     patterns[currentPattern] = newPattern()
  870.    
  871.     patterns[currentPattern].length = patterns[oldPattern].length
  872.     patterns[currentPattern].speed = patterns[oldPattern].speed
  873.     patterns[currentPattern].measure = patterns[oldPattern].measure
  874.  
  875.     for chkey, ch in pairs(patterns[oldPattern].channels) do
  876.         for noteskey, notes in pairs(ch.notes) do
  877.             patterns[currentPattern].channels[chkey].notes[noteskey] = notes
  878.         end
  879.     end
  880.  
  881.     currentSongPattern = songLength
  882.     song.patterns[currentSongPattern] = currentPattern
  883. end
  884.  
  885. -- Delete Pattern
  886. local function deletePattern()
  887.     if (songLength > 1) then
  888.         for i=currentSongPattern, songLength-1 do
  889.             song.patterns[i] = song.patterns[i+1] -- Starting from the current, i copy the next pattern 1 slot back
  890.         end
  891.         song.patterns[songLength] = nil
  892.         songLength = songLength-1
  893.         if (currentSongPattern > songLength) then
  894.             currentSongPattern = songLength
  895.         end
  896.         currentPattern = song.patterns[currentSongPattern]
  897.     end
  898. end
  899.  
  900. -- Change the song pattern number
  901. local function incrementPattern()
  902.     local nextPattern = song.patterns[currentSongPattern]+1
  903.     currentPattern = nextPattern
  904.     if (patterns[nextPattern] == nil) then
  905.         patterns[currentPattern] = newPattern()
  906.     end
  907.     song.patterns[currentSongPattern] = nextPattern
  908. end
  909.  
  910. -- Change the song pattern number
  911. local function decrementPattern()
  912.     local nextPattern = song.patterns[currentSongPattern]-1
  913.     if (nextPattern > 0) then
  914.         currentPattern = nextPattern
  915.         if (patterns[nextPattern] == nil) then
  916.             patterns[currentPattern] = newPattern()
  917.         end
  918.         song.patterns[currentSongPattern] = nextPattern
  919.     end
  920. end
  921.  
  922. -- Move pattern up
  923. local function movePatternUp()
  924.     if (currentSongPattern > 1) then
  925.         local aux = song.patterns[currentSongPattern-1]
  926.         song.patterns[currentSongPattern-1] = song.patterns[currentSongPattern]
  927.         song.patterns[currentSongPattern] = aux
  928.         currentSongPattern = currentSongPattern-1
  929.     end
  930. end
  931.  
  932. -- Move pattern up
  933. local function movePatternDown()
  934.     if (currentSongPattern < songLength) then
  935.         local aux = song.patterns[currentSongPattern+1]
  936.         song.patterns[currentSongPattern+1] = song.patterns[currentSongPattern]
  937.         song.patterns[currentSongPattern] = aux
  938.         currentSongPattern = currentSongPattern+1
  939.     end
  940. end
  941.  
  942. -- Place a note at a specific x, y coordinate on the screen
  943. local function placeNote(x, y, delayed)
  944.     local time, note = pixelToMusic(x,y,delayed)
  945.    
  946.     local notes = getCurrentNotes(time)
  947.     local done = false
  948.     -- See if the note is already there, if it is, delete it
  949.     for n=1, string.len(notes) do
  950.         local character = string.sub(notes, n, n)
  951.         if (character == note) then
  952.             notes = removeCharacterAt(notes, n)      
  953.             patterns[currentPattern].channels[currentChannel].notes[time] = notes
  954.             done = true
  955.             break
  956.         end
  957.     end
  958.     -- If there is no note there, add it
  959.     if (not done) then
  960.         notes = notes..note
  961.         patterns[currentPattern].channels[currentChannel].notes[time] = notes
  962.     end
  963.    
  964.     -- Play remaining notes
  965.     playSpecificBar(time, false)
  966.    
  967.     -- Redraw sheet
  968.     DrawScreen()
  969. end
  970.  
  971. -- Start
  972. newSong()
  973. song.patterns = {1}
  974. playSoundEffect("levelup", 0.5, 3)
  975. DrawScreen()
  976.  
  977. -- Update
  978. while true do
  979.     local event, a, b, c = os.pullEvent()
  980.     if (event == "timer") then
  981.         local completed = a
  982.         if (completed == playingTimer) then
  983.             if (playing) then
  984.                 local patternLength = patterns[currentPattern].length
  985.                 cursor = cursor+1
  986.                 if (cursor > patternLength) then
  987.                     currentSongPattern = currentSongPattern+1
  988.                     if (currentSongPattern > songLength) then
  989.                         currentSongPattern = 1
  990.                     end
  991.                     currentPattern = song.patterns[currentSongPattern]
  992.                     cursor = 1
  993.                     currentXOffset = 0
  994.                 end
  995.                 if (cursor > currentXOffset+beatsOnScreen) then
  996.                     currentXOffset = math.min(currentXOffset+beatsOnScreen, patternLength-beatsOnScreen)
  997.                 end
  998.                 playCurrentBar()
  999.                 DrawScreen()
  1000.                 playingTimer = os.startTimer(60/(songBpm*patterns[currentPattern].speed))
  1001.             end
  1002.         elseif (completed == delayedNoteTimer) then
  1003.             playCurrentBarDelayed()
  1004.         end
  1005.     elseif (event == "key") then
  1006.         local key = a
  1007.         if (key == keys.up) then
  1008.             scrollUp()
  1009.         elseif (key == keys.down) then
  1010.             scrollDown()
  1011.         elseif (key == keys.left) then
  1012.             scrollLeft()
  1013.         elseif (key == keys.right) then
  1014.             scrollRight()
  1015.         elseif (key == keys.leftShift) then
  1016.             pressingShift = true
  1017.         elseif (key == keys.space) then
  1018.             if (playing) then
  1019.                 pause()
  1020.             else
  1021.                 playFromCursor()
  1022.             end
  1023.             DrawScreen()
  1024.         elseif (key == keys.enter) then
  1025.             if (playing) then
  1026.                 stop()
  1027.             else
  1028.                 playFromStart()
  1029.             end
  1030.             DrawScreen()
  1031.         end
  1032.     elseif (event == "key_up") then
  1033.         local key = a
  1034.         if (key == keys.leftShift) then
  1035.             pressingShift = false
  1036.         end
  1037.     elseif (event == "mouse_scroll") then
  1038.         local scrollDirection = a
  1039.         if (scrollDirection == 1) then
  1040.             if (not pressingShift) then scrollDown()
  1041.             else scrollRight() end
  1042.         else
  1043.             if (not pressingShift) then scrollUp()
  1044.             else scrollLeft() end
  1045.         end
  1046.     elseif (event == "mouse_click") then
  1047.         local button = a
  1048.         local x = b
  1049.         local y = c
  1050.         -- Note Painter
  1051.         if (x > 3 and x < 4+math.min(beatsOnScreen, patterns[currentPattern].length)) then
  1052.             if (y > 2) then
  1053.                 if (button == 1) then
  1054.                     placeNote(x,y,false) -- Left click = normal note
  1055.                 else
  1056.                     placeNote(x,y,true) -- Right click = delayed note
  1057.                 end
  1058.             else
  1059.                 local time, note = pixelToMusic(x,y)
  1060.                 cursor = time
  1061.                 playCurrentBar()
  1062.                 DrawScreen()
  1063.             end
  1064.         else
  1065.  
  1066.             -- Panel
  1067.             local panelx = beatsOnScreen+3
  1068.  
  1069.             if (y == 1 and x > panelx+1 and x <= panelx+4) then
  1070.                 saveSong()
  1071.                 DrawScreen()
  1072.             end
  1073.  
  1074.             if (y == 1 and x > panelx+5 and x <= panelx+8) then
  1075.                 loadSong()
  1076.                 DrawScreen()
  1077.             end
  1078.  
  1079.             if (x > panelx+9 and y == 1) then -- Beat
  1080.                 term.setCursorPos(panelx+15, 1)
  1081.                 term.setBackgroundColor(colors.yellow)
  1082.                 term.setTextColor(colors.black)
  1083.                 term.write("   ")
  1084.                 term.setCursorPos(panelx+15, 1)
  1085.                 pause()
  1086.                 local newBPM = tonumber(read())
  1087.                 if (newBPM ~= nil) then
  1088.                     songBpm = math.floor(newBPM)
  1089.                 end
  1090.                 DrawScreen()
  1091.             end
  1092.  
  1093.             -- Patterns
  1094.             if (x > panelx+1 and x <= panelx+8) then
  1095.                 if (y == 3) then
  1096.                     prevSongPattern()
  1097.                 end
  1098.  
  1099.                 for i=4, 8 do
  1100.                     if (y == i) then
  1101.                         local selectedSongPattern = i-4+menuSongPatternScroll
  1102.                         if (selectedSongPattern <= songLength) then
  1103.                             currentSongPattern = selectedSongPattern
  1104.                             currentPattern = song.patterns[currentSongPattern]
  1105.                             DrawScreen()
  1106.                         end
  1107.                         break
  1108.                     end
  1109.                 end
  1110.  
  1111.                 if (y == 9) then
  1112.                     nextSongPattern()
  1113.                 end
  1114.             end
  1115.  
  1116.             -- Channels
  1117.             if (x > panelx+10 and x <= panelx+17) then
  1118.                 if (y == 3) then
  1119.                     prevChannel()
  1120.                 end
  1121.  
  1122.                 for i=4, 8 do
  1123.                     if (y == i) then
  1124.                         local selectedChannel = i-4+menuChannelScroll
  1125.                         if (selectedChannel <= instrumentCount) then
  1126.                             currentChannel = selectedChannel
  1127.                             playNote(currentChannel, 1, 1)
  1128.                             DrawScreen()
  1129.                         end
  1130.                         break
  1131.                     end
  1132.                 end
  1133.  
  1134.                 if (y == 9) then
  1135.                     nextChannel()
  1136.                 end
  1137.             end
  1138.  
  1139.             -- Pattern options
  1140.             if (x > panelx and x < panelx+8) then
  1141.  
  1142.    
  1143.                 if (y == 10) then -- repeat pattern
  1144.                     repeatPattern()
  1145.                     DrawScreen()
  1146.                 end
  1147.  
  1148.                 if (y == 11) then -- add pattern
  1149.                     addPattern()
  1150.                     DrawScreen()
  1151.                 end
  1152.  
  1153.                 if (y == 12) then -- move pattern up
  1154.                     movePatternUp()
  1155.                     DrawScreen()
  1156.                 end
  1157.  
  1158.                 if (y == 13) then -- move pattern down
  1159.                     movePatternDown()
  1160.                     DrawScreen()
  1161.                 end
  1162.             end
  1163.  
  1164.             if (x > panelx+9 and x < panelx+17) then
  1165.                 if (y == 11) then -- new pattern
  1166.                     duplicatePattern()
  1167.                     DrawScreen()
  1168.                 end
  1169.  
  1170.                 if (y == 12) then -- pattern +1
  1171.                     incrementPattern()
  1172.                     DrawScreen()
  1173.                 end
  1174.  
  1175.                 if (y == 13) then -- pattern -1
  1176.                     decrementPattern()
  1177.                     DrawScreen()
  1178.                 end
  1179.             end
  1180.  
  1181.             if (y == 14) then -- Velocidad
  1182.                 term.setCursorPos(panelx+13, 14)
  1183.                 term.setBackgroundColor(colors.yellow)
  1184.                 term.setTextColor(colors.black)
  1185.                 term.write("     ")
  1186.                 term.setCursorPos(panelx+13, 14)
  1187.                 pause()
  1188.                 local input = tonumber(read())
  1189.                 if (input ~= nil) then
  1190.                     local newspeed = math.max(0.1, input)
  1191.                     if (newspeed ~= nil) then
  1192.                         patterns[currentPattern].speed = newspeed
  1193.                     end
  1194.                 end
  1195.                 DrawPanel()
  1196.             end
  1197.  
  1198.             if (y == 15) then -- PatternLength
  1199.                 term.setCursorPos(panelx+9, 15)
  1200.                 term.setBackgroundColor(colors.yellow)
  1201.                 term.setTextColor(colors.black)
  1202.                 term.write("     ")
  1203.                 term.setCursorPos(panelx+9, 15)
  1204.                 pause()
  1205.                 local newLength = tonumber(read())
  1206.                 if (newLength ~= nil) then
  1207.                     patterns[currentPattern].length = math.floor(newLength)
  1208.                     defaultPatternLength = math.floor(newLength)
  1209.                 end
  1210.                 DrawScreen()
  1211.             end
  1212.  
  1213.             if (y == 16) then -- Beat
  1214.                 term.setCursorPos(panelx+9, 16)
  1215.                 term.setBackgroundColor(colors.yellow)
  1216.                 term.setTextColor(colors.black)
  1217.                 term.write("     ")
  1218.                 term.setCursorPos(panelx+9, 16)
  1219.                 pause()
  1220.                 local newBeat = tonumber(read())
  1221.                 if (newBeat ~= nil) then
  1222.                     patterns[currentPattern].measure = math.floor(newBeat)
  1223.                     defaultMeasure = math.floor(newBeat)
  1224.                 end
  1225.                 DrawScreen()
  1226.             end
  1227.        
  1228.          if (x > panelx and x < panelx+14 and y == 18) then
  1229.              clearInstrument()
  1230.              DrawScreen()
  1231.          end
  1232.             if (x > panelx and x < panelx+12 and y == 19) then -- delete pattern
  1233.                 deletePattern()
  1234.                 DrawScreen()
  1235.             end
  1236.         end
  1237.     end
  1238. end
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement