Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- --18107's Jukebox
- --version 1.2.0
- --last updated 13 November 2017
- --requires 'project red' or 'computronics'
- --Noteblock player at http://pastebin.com/aX8quTFy
- local monitor = peripheral.find("monitor")
- if monitor == nil then
- term.setTextColor(colors.red)
- print("Error: No monitor detected")
- return
- end
- local modem = peripheral.find("modem")
- local noteblock = peripheral.find("iron_noteblock")
- local musicList = {}
- local monitorWidth, monitorHeight = monitor.getSize()
- local currentlyPlaying = nil
- local screen = "list"
- local page = 1
- local repeatMode = "off" -- off, single, all ordered, all random
- local lastUpdate = 1
- local paused = false
- local timerRunning = false
- local songFinished = false
- local forceStop = false
- local songLength, songName, songAuth, origSongAuth, songDesc
- local tempo = 100
- local currentTick = 1
- local notes = {}
- function newLine()
- local x, y = monitor.getCursorPos()
- monitor.setCursorPos(1, y + 1)
- end --newline()
- function refreshMusicList()
- local length = #musicList
- local thisSong
- if currentlyPlaying ~= 0 and currentlyPlaying ~= nil then
- thisSong = musicList[currentlyPlaying]
- end
- local list = fs.list("")
- local disks = {}
- musicList = {}
- local songCounter = 1
- local diskCounter = 1
- --get music from computer, get list of disks
- for i = 1, #list do
- if string.sub(list[i],-4) == ".nbs" then
- musicList[songCounter] = list[i]
- songCounter = songCounter + 1
- elseif string.sub(list[i],0,4) == "disk" and fs.isDir(list[i]) then
- disks[diskCounter] = list[i]
- diskCounter = diskCounter + 1
- end
- end --for #list
- --get music from disks
- for a = 1, #disks do
- list = fs.list(disks[a])
- for b = 1, #list do
- if string.sub(list[b],-4) == ".nbs" then
- musicList[songCounter] = disks[a].."/"..list[b]
- songCounter = songCounter + 1
- end --if
- end --for #list
- end --for #disks
- --if song does not exist, stop playing it
- if currentlyPlaying ~= 0 and currentlyPlaying ~= nil then
- if thisSong ~= musicList[currentlyPlaying] then
- currentlyPlaying = 0
- end --if thisSong
- end --if currentlyPlaying
- --check if musicList has shrunk, and decrease page number if needed
- if page > #musicList/(monitorHeight-3) and #musicList > 0 then
- page = math.ceil(#musicList/(monitorHeight-3))
- end --if page
- end --refreshMusicList()
- function displayMusicList()
- --draw top line
- monitor.clear()
- monitor.setCursorPos(monitorWidth-4-20, 1)
- monitor.setTextColor(colors.yellow)
- monitor.write("Repeat: "..repeatMode)
- monitor.setCursorPos(1, 1)
- monitor.setTextColor(colors.cyan)
- monitor.write("18107's Juke Box")
- monitor.setCursorPos(monitorWidth-3, 1)
- monitor.setTextColor(colors.red)
- monitor.write("Stop")
- monitor.setTextColor(colors.white)
- newLine()
- --draw songs
- if #musicList > 0 then
- for i = (monitorHeight-3)*(page-1)+1, (monitorHeight-3)*(page-1)+monitorHeight-3 do
- if currentlyPlaying == i then
- monitor.setTextColor(colors.blue)
- else
- monitor.setTextColor(colors.white)
- end --if currentlyPlaying
- if i < #musicList then
- if string.sub(musicList[i],0,4) == "disk" then
- if string.sub(musicList[i],5,5) == "/" then
- monitor.write("Disk : "..string.sub(musicList[i],6,-5))
- else
- monitor.write("Disk "..string.sub(musicList[i],5,5).." : "..string.sub(musicList[i],7,-5))
- end --if "/"
- else
- monitor.write(string.sub(musicList[i],0,-5))
- end --if disk
- end --if #musicList
- newLine()
- end --for
- end --if #musicList
- --draw second bottom line
- monitor.setCursorPos(1, monitorHeight-1)
- if currentlyPlaying == 0 or currentlyPlaying == nil then
- monitor.setTextColor(colors.lightGray)
- else
- monitor.setTextColor(colors.cyan)
- end --if currentlyPlaying
- monitor.write("Currently Playing")
- monitor.setCursorPos(monitorWidth-9, monitorHeight-1)
- if currentlyPlaying ~= 0 and currentlyPlaying ~= nil then
- monitor.setTextColor(colors.red)
- end --if currentlyPlaying
- if paused then
- monitor.write("Play ")
- else
- monitor.write("Pause ")
- end --if paused
- if currentlyPlaying ~= 0 and currentlyPlaying ~= nil then
- monitor.setTextColor(colors.blue)
- end --if currentlyPlaying
- monitor.write("Skip")
- --draw bottom line
- monitor.setTextColor(colors.green)
- monitor.setCursorPos(1, monitorHeight)
- monitor.write("Previous")
- monitor.setCursorPos(monitorWidth-3, monitorHeight)
- monitor.write("Next")
- monitor.setTextColor(colors.yellow)
- monitor.setCursorPos(monitorWidth/2+1, monitorHeight)
- monitor.write(tostring(page))
- end --displayMusicList()
- function displayCurrentlyPlaying()
- --draw top line
- monitor.clear()
- monitor.setCursorPos(monitorWidth-4-20, 1)
- monitor.setTextColor(colors.yellow)
- monitor.write("Repeat: "..repeatMode)
- monitor.setCursorPos(1, 1)
- monitor.setTextColor(colors.cyan)
- monitor.write("18107's Juke Box")
- monitor.setCursorPos(monitorWidth-3, 1)
- monitor.setTextColor(colors.red)
- monitor.write("Stop")
- monitor.setTextColor(colors.white)
- newLine()
- newLine()
- --song info
- if string.sub(musicList[currentlyPlaying],0,4) == "disk" then
- if string.sub(musicList[currentlyPlaying],5,5) == "/" then
- monitor.write("Disk :"..string.sub(musicList[currentlyPlaying],6,-5))
- else
- monitor.write("Disk "..string.sub(musicList[currentlyPlaying],5,5).." : "..string.sub(musicList[currentlyPlaying],7,-5))
- end --if "/"
- else
- monitor.write(string.sub(musicList[currentlyPlaying],0,-5))
- end --if disk
- newLine()
- newLine()
- if type(songAuth) == "string" then
- monitor.write("Author: "..songAuth)
- end --if songAuth
- newLine()
- newLine()
- if type(origSongAuth) == "string" then
- monitor.write("Original author: "..origSongAuth)
- end --if origSongAuth
- newLine()
- newLine()
- if type(songDesc) == "string" then
- for desc = 0, #songDesc/monitorWidth+1 do
- monitor.write(string.sub(songDesc, desc*monitorWidth+1, (desc+1)*monitorWidth))
- newLine()
- end --for desc
- end --songDesc
- --second bottom line
- monitor.setCursorPos(1, monitorHeight-1)
- monitor.setTextColor(colors.cyan)
- monitor.write("Song list")
- monitor.setCursorPos(monitorWidth-9, monitorHeight-1)
- monitor.setTextColor(colors.red)
- if paused then
- monitor.write("Play ")
- else
- monitor.write("Pause ")
- end --if paused
- monitor.setTextColor(colors.blue)
- monitor.write("Skip")
- --bottom line
- monitor.setTextColor(colors.lightGray)
- local minutes = math.floor(songLength*100/tempo/60) --right side
- local seconds = math.floor(songLength*100/tempo) % 60
- monitor.setCursorPos(monitorWidth-4, monitorHeight)
- if minutes < 10 then
- monitor.write(" ")
- end --if minutes
- monitor.write(minutes..":")
- if seconds < 10 then
- monitor.write("0")
- end --if seconds
- monitor.write(seconds.."")
- minutes = math.floor(currentTick*100/tempo/60)--left side
- seconds = math.floor(currentTick*100/tempo) % 60
- monitor.setCursorPos(1, monitorHeight)
- if minutes < 10 then
- monitor.write(" ")
- end --if minutes
- monitor.write(minutes..":")
- if seconds < 10 then
- monitor.write("0")
- end --if seconds
- monitor.write(seconds.."")
- monitor.write(" <") --center
- for i = 8, monitorWidth-7 do
- monitor.write("=")
- end --for monitorWidth
- monitor.write(">")
- monitor.setCursorPos((currentTick/songLength)*(monitorWidth-14)+8, monitorHeight)
- monitor.write("|")
- end --displayCurrentlyPlaying
- function refreshDisplay()
- if screen == "list" then
- displayMusicList()
- elseif screen == "playing" then
- displayCurrentlyPlaying()
- end --if screen
- end --refreshDisplay()
- function readNumber(file, size)
- local number = 0
- for siz = 1, size do
- number = number + bit.blshift(file.read(), 8*(siz-1))
- end --for size
- return number
- end --readNumber()
- function readString(file, length)
- if length ~= 0 then
- local text = string.char(file.read())
- for char = 2, length do
- text = text..string.char(file.read())
- end --for char
- return text
- end --if length
- end --readString()
- function loadSong()
- local song = fs.open(musicList[currentlyPlaying], "rb")
- if song == nil then
- print("File not found")
- currentlyPlaying = 0
- return
- end --if nil
- --header
- local strLen = 0
- songLength = readNumber(song, 2) --song length (in ticks)
- readNumber(song, 2) --song height
- strLen = readNumber(song, 4)
- songName = readString(song, strLen) --song name
- strLen = readNumber(song, 4)
- songAuth = readString(song, strLen) --song author
- strLen = readNumber(song, 4)
- origSongAuth = readString(song, strLen) --original song author
- strLen = readNumber(song, 4)
- songDesc = readString(song, strLen) --song description
- tempo = readNumber(song, 2) --tempo (ticks per second x100)
- readNumber(song, 1) --auto saving
- readNumber(song, 1) --auto saving duration
- readNumber(song, 1) --time signature
- readNumber(song, 4) --minutes spent
- readNumber(song, 4) --left clicks
- readNumber(song, 4) --right clicks
- readNumber(song, 4) --blocks added
- readNumber(song, 4) --blocks removed
- strLen = readNumber(song, 4)
- readString(song, strLen) --MIDI/schematic file name
- local tick = 1
- local nextTick = 1
- local hasNext = true
- local instrument = 0
- local key = 0
- local chord = 1
- currentTick = 1
- notes = {}
- --read song
- while hasNext do
- nextTick = readNumber(song, 2)
- while nextTick > 1 do
- notes[tick] = {}
- tick = tick + 1
- nextTick = nextTick - 1
- end --while nextTick
- if nextTick ~= 0 then
- notes[tick] = {}
- chord = 1
- while readNumber(song, 2) ~= 0 do --play chord
- instrument = readNumber(song, 1)
- key = readNumber(song, 1)
- notes[tick][chord] = {instrument, key}
- chord = chord + 1
- end --while readNumber
- tick = tick + 1
- else
- hasNext = false
- end --if nextTick
- end --while hasNext
- song.close()
- if timerRunning == false then
- timerRunning = true
- os.startTimer(100/tempo)
- end --if timerRunning
- end --loadSong()
- function nextSong()
- if currentlyPlaying ~= 0 and currentlyPlaying ~= nil then
- if repeatMode == "all random" then
- currentlyPlaying = math.random(#musicList)
- elseif repeatMode == "all ordered" then
- currentlyPlaying = currentlyPlaying + 1
- if currentlyPlaying >= #musicList then
- currentlyPlaying = 1
- end --if #musicList
- elseif repeatMode == "off" then
- currentlyPlaying = 0
- songFinished = true
- screen = "list"
- end --if repeatMode
- end --if currentlyPlaying
- if currentlyPlaying ~= 0 and currentlyPlaying ~= nil then
- page = math.floor((currentlyPlaying-1)/(monitorHeight-3)) + 1
- loadSong()
- end --if currentlyPlaying
- end --nextSong()
- function playNote(instrument, key)
- if noteblock ~= nil then
- if instrument == 0 then
- noteblock.playNote(0, key-33)
- elseif instrument == 1 then
- noteblock.playNote(4, key-33)
- else
- noteblock.playNote(instrument-1, key-33)
- end --if instrument
- end --if noteblock
- if modem ~= nil then
- modem.transmit(instrument, 0, bit.blshift(1, key-33))
- end --if modem
- end --playNote()
- function transmitNotes(notes)
- if modem ~= nil then
- for instrument = 1, 5 do
- modem.transmit(instrument, 0, notes[instrument])
- end --for i
- end --if modem
- end --transmitNotes
- function playSong()
- local modemData = {0, 0, 0, 0, 0}
- if not paused then
- if notes[currentTick] ~= nil then
- if (#notes[currentTick] ~= 0) then
- for _,note in pairs(notes[currentTick]) do
- playNote(note[1], note[2])
- if note[2] >= 33 then
- modemData[note[1]+1] = bit.bor(modemData[note[1]+1], bit.blshift(1, note[2]-33))
- end
- end --for notes
- transmitNotes(modemData)
- end --if #notes
- currentTick = currentTick + 1
- else
- songFinished = true
- end --if notes
- end --if not paused
- end --playSong()
- function monitorTouch(x, y)
- if screen == "list" then
- --top line
- if y == 1 then
- if x > monitorWidth-4 then --stop
- forceStop = true
- paused = false
- elseif x > 16 and x <= monitorWidth-6 then --repeatMode
- if repeatMode == "off" then
- repeatMode = "single"
- elseif repeatMode == "single" then
- repeatMode = "all ordered"
- elseif repeatMode == "all ordered" then
- repeatMode = "all random"
- else--if repeatMode == "all random" then
- repeatMode = "off"
- end --if repeatMode
- end --x
- --bottom line
- elseif y == monitorHeight then
- if x < 9 then --previous
- if page > 1 then
- page = page - 1
- end --if page
- elseif x > monitorWidth-4 then --next
- if page*(monitorHeight-3) < #musicList then
- page = page + 1
- end --if page
- end --if x
- --second bottom line
- elseif y == monitorHeight-1 then
- if x <= 17 then --currentlyPlaying
- if currentlyPlaying ~= 0 and currentlyPlaying ~= nil then
- screen = "playing"
- end --if currentlyPlaying
- elseif x >= monitorWidth-9 and x < monitorWidth-4 then --pause
- paused = not paused
- elseif x >= monitorWidth-3 then --skip
- nextSong()
- end --if x
- --song list
- else
- currentlyPlaying = (y-1) + (page-1)*(monitorHeight-3)
- loadSong()
- if forceStop then
- forceStop = false
- end --if forceStop
- end --if y
- elseif screen == "playing" then
- --top line
- if y == 1 then
- if x > monitorWidth-4 then --stop
- forceStop = true
- paused = false
- elseif x > 16 and x <= monitorWidth-6 then --repeatMode
- if repeatMode == "off" then
- repeatMode = "single"
- elseif repeatMode == "single" then
- repeatMode = "all ordered"
- elseif repeatMode == "all ordered" then
- repeatMode = "all random"
- else--if repeatMode == "all random" then
- repeatMode = "off"
- end --if repeatMode
- end --if x
- --second bottom line
- elseif y == monitorHeight-1 then
- if x <= 9 then --song list
- screen = "list"
- elseif x >= monitorWidth-9 and x < monitorWidth-4 then --pause
- paused = not paused
- elseif x >= monitorWidth-3 then --skip
- nextSong()
- end --if x
- --bottom line
- elseif y == monitorHeight then
- if x == 8 then
- currentTick = 1
- elseif x >= 8 and x <= monitorWidth-7 then
- currentTick = math.floor((x-8)/(monitorWidth-14)*songLength+0.5)
- end --if x
- end --if y
- end --if screen
- refreshDisplay()
- end --monitorTouch
- function start()
- math.randomseed(os.time())
- math.random()
- refreshMusicList()
- displayMusicList()
- end --start()
- function run()
- local running = true
- local event, side, x, y
- while running do
- event, side, x, y = os.pullEventRaw()
- if event == "terminate" then
- running = false
- elseif event == "monitor_touch" then
- monitorTouch(x, y)
- elseif event == "timer" then
- if forceStop == true then
- forceStop = false
- timerRunning = false
- currentlyPlaying = 0
- screen = "list"
- refreshDisplay()
- else
- if songFinished then
- nextSong()
- songFinished = false
- timerRunning = false
- refreshDisplay()
- else
- os.startTimer(100/tempo)
- playSong()
- if math.floor(currentTick*100/tempo) ~= math.floor(lastUpdate*100/tempo) then
- lastUpdate = currentTick
- refreshDisplay()
- end --if lastUpdate
- end --if not songFinished
- end --if forceStop
- elseif event == "peripheral" or event == "peripheral_detach" or event == "monitor_resize" then
- --reload everything
- modem = peripheral.find("modem")
- noteblock = peripheral.find("iron_noteblock")
- monitor = peripheral.find("monitor")
- if monitor == nil then
- term.setTextColor(colors.red)
- print("Error: monitor detached")
- return
- end --if monitor
- monitorWidth, monitorHeight = monitor.getSize()
- refreshDisplay()
- end --if event
- end --while running
- end --run()
- function stop()
- monitor.clear()
- end --stop()
- start()
- run()
- stop()
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement