Advertisement
Guest User

memdiaplayer

a guest
Jan 27th, 2020
216
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Lua 11.84 KB | None | 0 0
  1. local redstoneInputSide = "left"
  2. local diskSide = "bottom"
  3.  
  4. local songBpm = 240
  5. local songLength = 1
  6. local songCursor = 1
  7. local songBeats = 0
  8.  
  9. local sp = {}
  10. local _i = 0
  11. for i=0, 60 do
  12.     local p = peripheral.wrap("speaker_"..i)
  13.     if (p ~= nil) then
  14.         sp[_i] = p
  15.         _i = _i+1
  16.     end
  17. end
  18.  
  19. local nextSpeaker = 0
  20. local speakerCount = table.getn(sp)
  21.  
  22. local instrumentCount = 11
  23. local instruments = {
  24.     -- musical
  25.     {["name"] = "piano", ["file"] = "block.note.harp"},
  26.     {["name"] = "bass", ["file"] = "block.note.bass"},
  27.     {["name"] = "bell", ["file"] = "block.note.bell"},
  28.     {["name"] = "chime", ["file"] = "block.note.chime"},
  29.     {["name"] = "xhylophone", ["file"] = "block.note.xylophone"},
  30.     {["name"] = "flute", ["file"] = "block.note.flute"},
  31.     {["name"] = "guitar", ["file"] = "block.note.guitar"},
  32.     {["name"] = "kick", ["file"] = "block.note.basedrum"},
  33.     {["name"] = "hat", ["file"] = "block.note.hat"},
  34.     {["name"] = "cimbal", ["file"] = "block.sand.break"},
  35.     {["name"] = "snare", ["file"] = "block.note.snare"},
  36.     -- sfx
  37.     {["name"] = "levelup", ["file"] ="entity.player.levelup"}
  38. }
  39.  
  40. local song = {}
  41. local patterns = {}
  42.  
  43. local currentPattern = 1
  44. local currentSongPattern = 1
  45. local cursor = 1
  46. local playing = false
  47.  
  48. local playingTimer = nil
  49. local delayedNoteTimer = nil
  50. local delayedAllChannels = false
  51. local delayTime = 1
  52.  
  53. local progressTimer = nil
  54.  
  55. -- Data of the current pattern
  56. local function getCurrentNotes(time)
  57.     local notes = patterns[currentPattern].channels[currentChannel].notes[time]
  58.     if (notes == nil) then
  59.         return ""
  60.     else
  61.         return notes
  62.     end
  63. end
  64.  
  65. -- Data of the pattern for the specified channel
  66. local function getChannelNotes(channel, time)
  67.     local notes = patterns[currentPattern].channels[channel].notes[time]
  68.     if (notes == nil) then
  69.         return ""
  70.     else
  71.         return notes
  72.     end
  73. end
  74.  
  75. -- Get an instrument by name
  76. local function getInstrumentByName(name)
  77.     for k, v in pairs(instruments) do
  78.         if (v.name == name) then
  79.             return v
  80.         end
  81.     end
  82.     error("Invalid instrument name")
  83. end
  84.  
  85. -- Get an instrument ID by name
  86. local function getInstrumentIDByName(name)
  87.     for i=1, instrumentCount do
  88.         if (instruments[i].name == name) then
  89.             return i
  90.         end
  91.     end
  92.     error("Invalid instrument name")
  93. end
  94.  
  95. -- Note character to note number
  96. local function characterToNote(c)
  97.     local delayed = true
  98.     if (string.byte(c) >= 97) then
  99.         delayed = false
  100.     end
  101.    
  102.     if (delayed) then
  103.         return string.byte(c)-65, delayed
  104.     else
  105.         return string.byte(c)-97, delayed
  106.     end
  107. end
  108.  
  109. -- Note number to note character
  110. local function noteToCharacter(n, delayed)
  111.     if (delayed) then
  112.         return string.char(tonumber(n)+65) --Mayuscula
  113.     else
  114.         return string.char(tonumber(n)+97) --minuscula
  115.     end
  116. end
  117.  
  118. -- Pitch of a note number
  119. local function notePitch(n)
  120.     return math.pow(2, (n-12)/12)
  121. end
  122.  
  123. -- Pitch of a note character
  124. local function charPitch(c)
  125.     return notePitch(characterToNote(c))
  126. end
  127.  
  128. local function playSoundEffect(soundname, vol, pitch)
  129.     sp[nextSpeaker].playSound(getInstrumentByName(soundname).file, vol, pitch)
  130.     nextSpeaker = nextSpeaker+1
  131.     if (nextSpeaker > speakerCount) then
  132.         nextSpeaker = 0
  133.     end
  134. end
  135.  
  136. -- Play a single note number
  137. local function playNote(inst, vol, note)
  138.     sp[nextSpeaker].playSound(instruments[inst].file, 0.4, note)
  139.     nextSpeaker = nextSpeaker+1
  140.     if (nextSpeaker > speakerCount) then
  141.         nextSpeaker = 0
  142.     end
  143. end
  144.  
  145. -- Play a string of notes
  146. local function playBar(inst, vol, notes, delayed)
  147.     for n=1, string.len(notes) do
  148.         local note = string.sub(notes, n, n)
  149.         if (delayed and string.byte(note) < 97) then -- If its delayed, play only uppercases
  150.             playNote(inst, vol, charPitch(note))
  151.         elseif (not delayed and string.byte(note) >= 97) then -- If not, play only lowercases
  152.             playNote(inst, vol, charPitch(note))
  153.         end
  154.     end
  155. end
  156.  
  157. -- Play the delayed bar
  158. local function playCurrentBarDelayed()
  159.     if (delayedAllChannels) then
  160.         for i=1, instrumentCount do
  161.             playBar(i, 1, getChannelNotes(i, delayTime), true)
  162.         end
  163.     else
  164.         playBar(currentChannel, 1, getCurrentNotes(delayTime), true)
  165.     end
  166. end
  167.  
  168. -- Play the bar at a specified time
  169. local function playSpecificBar(time, allChannels)
  170.     delayTime = time
  171.     if (allChannels) then
  172.         for i=1, instrumentCount do
  173.             playBar(i, 1, getChannelNotes(i, time), false)
  174.         end
  175.     else
  176.         playBar(currentChannel, 1, getCurrentNotes(time), false)
  177.     end
  178.     delayedNoteTimer = os.startTimer(30/(songBpm*patterns[currentPattern].speed)-0.001)
  179.     delayedAllChannels = allChannels
  180. end
  181.  
  182. -- Play the current channel's bar currently indicated by the cursor
  183. local function playCurrentChannelBar()
  184.     playSpecificBar(cursor, false)
  185. end
  186.  
  187. -- Play the every bar currently indicated by the cursor
  188. local function playCurrentBar()
  189.     playSpecificBar(cursor, true)
  190. end
  191.  
  192. local function updateProgress()
  193.     term.setCursorPos(6, 13)
  194.     local percent = songCursor/songBeats
  195.     local characters = math.ceil(percent*40)
  196.     term.setBackgroundColor(colors.orange)
  197.     term.write(string.rep(" ", characters))
  198.     term.setBackgroundColor(colors.brown)
  199.     term.write(string.rep(" ", 40-characters))
  200.     term.setBackgroundColor(colors.black)
  201. end
  202.  
  203. -- StartPlaying
  204. local function playFromCursor()
  205.     if (songBeats > 0) then
  206.         playing = true
  207.         playingTimer = os.startTimer(60/(songBpm*patterns[currentPattern].speed))
  208.         progressTimer = os.startTimer(1)
  209.         updateProgress()
  210.         playCurrentBar()
  211.         term.setCursorPos(5, 12)
  212.         term.setTextColor(colors.lime)
  213.         term.write(" > Play        ")
  214.     end
  215. end
  216.  
  217. -- StartPlaying
  218. local function playFromStart()
  219.     if (not loadSong()) then return end
  220.     cursor = 1
  221.     songCursor = 1
  222.     currentXOffset = 0
  223.     playing = true
  224.     playingTimer = os.startTimer(60/(songBpm*patterns[currentPattern].speed))
  225.     progressTimer = os.startTimer(1)
  226.     updateProgress()
  227.     playCurrentBar()
  228.     term.setCursorPos(5, 12)
  229.     term.setTextColor(colors.lime)
  230.     term.write("|> Play         ")
  231. end
  232.  
  233. -- Pause
  234. local function stop()
  235.     playing = false
  236.     cursor = 1
  237.     songCursor = 1
  238.     term.setCursorPos(5, 12)
  239.     term.setTextColor(colors.red)
  240.     term.write("[] Stop     ")
  241. end
  242.  
  243. -- Pause
  244. local function pause()
  245.     playing = false
  246.     term.setCursorPos(5, 12)
  247.     term.setTextColor(colors.red)
  248.     term.write("|| Pause    ")
  249. end
  250.  
  251. local function newPattern()
  252.     local p = {
  253.         ["channels"] = {},
  254.         ["length"] = defaultPatternLength,
  255.         ["speed"] = 1,
  256.         ["measure"] = defaultMeasure
  257.     }
  258.     for i=1, instrumentCount do
  259.         p.channels[i] = {
  260.             ["notes"] = {}
  261.         }
  262.     end
  263.     return p
  264. end
  265.  
  266. local function newSong()
  267.     song = {
  268.         ["patterns"] = {}
  269.     }
  270.     currentPattern = 1
  271.     patterns[currentPattern] = newPattern()
  272. end
  273.  
  274. -- Load song from disk
  275. function loadSong()
  276.  if (disk.isPresent(diskSide)) then
  277.     local f = fs.open("disk/memsong.txt", "r")
  278.  if (f == nil) then
  279.      return false
  280.  end
  281.     local fileTitle = "unknown"
  282.     local fileBpm = 240
  283.     local fileSong = {}
  284.  
  285.     newSong()
  286.     patterns = {}
  287.  songBeats = 0
  288.  
  289.     local line = f.readLine()
  290.  
  291.     repeat
  292.         if (line == "title") then
  293.             fileTitle = f.readLine()
  294.         elseif (line == "bpm") then
  295.             fileBpm = tonumber(f.readLine())
  296.         elseif (line == "structure") then
  297.             local songPart = f.readLine()
  298.             local i=1
  299.             repeat
  300.                 fileSong[i] = tonumber(songPart)
  301.                 i = i+1
  302.                 songPart = f.readLine()
  303.             until songPart == ""
  304.         elseif (line == "pattern") then
  305.             local currentPattern = tonumber(f.readLine())
  306.             if (currentPattern ~= nil) then
  307.                 patterns[currentPattern] = newPattern()
  308.                 local pLine = f.readLine()
  309.                 repeat
  310.                     local broken = false
  311.                     if (pLine == "length") then
  312.                         patterns[currentPattern].length = tonumber(f.readLine())
  313.                     elseif (pLine == "measure") then
  314.                         patterns[currentPattern].measure = tonumber(f.readLine())
  315.                     elseif (pLine == "speed") then
  316.                         patterns[currentPattern].speed = tonumber(f.readLine())
  317.                     elseif (pLine == "notes") then
  318.                         local instrument = f.readLine()
  319.                         if (instrument ~= "") then
  320.                             repeat
  321.                                 local noteString = f.readLine()
  322.                                 local notes = {}
  323.                                 local pointer = 1
  324.                                 local spaces = 0
  325.  
  326.                                 for i=1, string.len(noteString) do
  327.                                    
  328.                                     local char = string.sub(noteString, i, i)
  329.  
  330.                                     if (tonumber(char)) then -- If the character is a number, count spaces
  331.                                         spaces = spaces*10
  332.                                         spaces = spaces+tonumber(char)
  333.                                     else
  334.                                         pointer = pointer+spaces
  335.                                         if (notes[pointer] == nil) then
  336.                                             notes[pointer] = ""
  337.                                         end
  338.                                         notes[pointer] = notes[pointer]..char
  339.                                         spaces = 0
  340.                                     end
  341.                                 end
  342.  
  343.                                 patterns[currentPattern].channels[getInstrumentIDByName(instrument)].notes = notes
  344.                                 songBeats = songBeats + patterns[currentPattern].length
  345.  
  346.                                 instrument = f.readLine()
  347.                             until instrument == ""
  348.                             broken = true
  349.                         end
  350.                     end
  351.                     if (broken) then
  352.                         pLine = nil
  353.                     else
  354.                         pLine = f.readLine()
  355.                     end
  356.                 until pLine == "" or pLine == nil
  357.             end
  358.         end
  359.         line = f.readLine()
  360.     until line == "" or line == nil
  361.     f.close()
  362.  
  363.     song.patterns = fileSong
  364.     songLength = #song.patterns
  365.  songBeats = 0
  366.  for i=1, songLength do
  367.      songBeats = songBeats+patterns[song.patterns[i]].length
  368.  end
  369.     songBpm = fileBpm
  370.     currentSongPattern = 1
  371.     currentPattern = song.patterns[1]
  372.  
  373.  term.setCursorPos(1, 8)
  374.  term.setBackgroundColor(colors.black)
  375.  term.setTextColor(colors.yellow)
  376.  term.write("                                                  ")
  377.  term.setCursorPos(1, 8)
  378.  term.write("Cancion: "..fileTitle)
  379.  return true
  380.  else
  381.  return false
  382.  end
  383. end
  384.  
  385. term.clear()
  386. term.setCursorPos(1,1)
  387. term.setBackgroundColor(colors.black)
  388. term.setTextColor(colors.orange)
  389. print("~ Memdia Player ~")
  390. print("")
  391. print("Enter: Cargar canción / Iniciar desde el principio / Pausa")
  392. print("Espacio: Pausa / Play")
  393.  
  394. -- Update
  395. while true do
  396.     local event, a, b, c = os.pullEvent()
  397.     if (event == "timer") then
  398.         local completed = a
  399.         if (completed == playingTimer) then
  400.             if (playing) then
  401.                 local patternLength = patterns[currentPattern].length
  402.                 cursor = cursor+1
  403.                 songCursor = songCursor+1
  404.                 if (cursor > patternLength) then
  405.                     currentSongPattern = currentSongPattern+1
  406.                     if (currentSongPattern > songLength) then
  407.                     if (redstoneInputSide ~= nil) then
  408.                         while (not rs.getInput(redstoneInputSide)) do
  409.                             os.pullEvent("redstone")
  410.                         end
  411.                      end
  412.                         currentSongPattern = 1
  413.                         songCursor = 1
  414.                         updateProgress()
  415.                     end
  416.                     currentPattern = song.patterns[currentSongPattern]
  417.                     cursor = 1
  418.                     currentXOffset = 0
  419.                 end
  420.                 playCurrentBar()
  421.                 playingTimer = os.startTimer(60/(songBpm*patterns[currentPattern].speed))
  422.             end
  423.         elseif (completed == delayedNoteTimer) then
  424.             playCurrentBarDelayed()
  425.         elseif (completed == progressTimer) then
  426.             if (playing) then
  427.                 updateProgress()
  428.                 progressTimer = os.startTimer(1)
  429.             end
  430.         end
  431.     elseif (event == "key") then
  432.         local key = a
  433.         if (key == keys.space) then
  434.             if (playing) then
  435.                 pause()
  436.             else
  437.                 playFromCursor()
  438.             end
  439.            
  440.         elseif (key == keys.enter) then
  441.             if (playing) then
  442.                 pause()
  443.             else
  444.                 playFromStart()
  445.             end
  446.            
  447.         end
  448.     end
  449. end
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement