Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- --18107's Jukebox
- --version 1.1.2
- --last updated 14 July 2015
- --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 musicList = {}
- local monitorWidth, monitorHeight = monitor.getSize()
- local song = nil
- local playing = nil
- local songLength, songName, songAuth, origSongAuth, songDesc
- local tempo = 1000
- local page = 1
- local screen = 1
- local noteblock = peripheral.find("iron_noteblock")
- local instrum = {0, 0, 0, 0, 0}
- local repeatMode = "off" -- off, single, all ordered, all random
- local finished = false
- local refreshCounter = 1
- local ticksPlayed = 0
- local updateNeeded = false
- local paused = false
- math.randomseed(os.time())
- math.random()
- function newLine()
- local x, y = monitor.getCursorPos()
- monitor.setCursorPos(1, y + 1)
- end --newline()
- function readNumber(file, size) --reads a binary number
- 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 return end
- local text = string.char(file.read())
- for char = 2, length do
- text = text..string.char(file.read())
- end --for char
- return text
- end --readString()
- function refreshMusicList()
- local length = #musicList
- local thisSong
- if playing ~= 0 and playing ~= nil then
- thisSong = musicList[playing]
- end --if playing
- local list = fs.list("")
- local disks = {}
- musicList = {}
- local counter = 1
- local counter2 = 1
- for i = 1, #list do
- if string.sub(list[i],-4)==".nbs" then
- musicList[counter] = list[i]
- counter = counter + 1
- elseif string.sub(list[i],0,4) == "disk" and fs.isDir(list[i]) then
- disks[counter2] = list[i]
- counter2 = counter2 + 1
- end --if ".nbs"
- end --for #list
- for a = 1, #disks do
- list = fs.list(disks[a])
- for b = 1, #list do
- if string.sub(list[b],-4)==".nbs" then
- musicList[counter] = disks[a].."/"..list[b]
- counter = counter + 1
- end --if ".nbs"
- end --for #list
- end --for #disks
- if playing ~= 0 and playing ~= nil then
- if thisSong ~= musicList[playing] then
- playing = playing - length + #musicList --FIXME check if this worked
- updateNeeded = true
- end --if thisSong
- end --if playing
- if page > #musicList/(monitorHeight-3) and #musicList > 0 then
- page = math.ceil(#musicList/(monitorHeight-3))
- end --if page
- end --refreshMusicList()
- function nextSong()
- if playing == 0 or playing == nil then return end
- if repeatMode == "all random" then
- playing = math.random(#musicList)
- else
- if playing >= #musicList then
- playing = 0
- end --if playing == #musicList
- playing = playing + 1
- end --if repeatMode
- page = math.floor((playing-1)/(monitorHeight-3)) + 1
- updateNeeded = true
- end --skip()
- function displayMusicList(page, playing)
- refreshMusicList()
- 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()
- if #musicList > 0 then
- for i = (monitorHeight-3)*(page-1)+1, (monitorHeight-3)*(page-1)+monitorHeight-3 do
- if playing == i then monitor.setTextColor(colors.blue) end
- 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
- if playing == i then monitor.setTextColor(colors.white) end
- newLine()
- end --for 1, 16
- end --if #musicList
- monitor.setCursorPos(1, monitorHeight-1)
- if playing == 0 or playing == nil then
- monitor.setTextColor(colors.lightGray)
- else
- monitor.setTextColor(colors.cyan)
- end --if playing
- monitor.write("Currently Playing")
- monitor.setCursorPos(monitorWidth-9, monitorHeight-1)
- if paused then
- monitor.write("Play ")
- else
- monitor.write("Pause ")
- end --if paused
- if playing ~= 0 and playing ~= nil then
- monitor.setTextColor(colors.blue)
- end --if playing
- monitor.write("Skip")
- newLine()
- monitor.setTextColor(colors.green)
- monitor.write("Previous")
- monitor.setCursorPos(monitorWidth-3, monitorHeight)
- monitor.write("Next")
- monitor.setCursorPos(monitorWidth/2+1, monitorHeight)
- monitor.setTextColor(colors.yellow)
- monitor.write(tostring(page))
- monitor.setTextColor(colors.white)
- end --displayMusicList()
- function displayCurrentlyPlaying(playing, full)
- if full then
- 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()
- if string.sub(musicList[playing], 0, 4) == "disk" then
- if string.sub(musicList[playing], 5, 5) == "/" then
- monitor.write("Disk : "..string.sub(musicList[playing], 6, -5))
- else
- monitor.write("Disk "..string.sub(musicList[playing],5,5).." : "..string.sub(musicList[playing],7,-5))
- end --if "/"
- else
- monitor.write(string.sub(musicList[playing], 0, -5))
- end --if disk/
- newLine()
- newLine()
- if type(songAuth) == "string" then
- monitor.write("Author: "..songAuth)
- end --if string
- newLine()
- newLine()
- if type(origSongAuth) == "string" then
- monitor.write("Original author: "..origSongAuth)
- end --if string
- 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 #songDesc
- end --if string
- monitor.setCursorPos(1, monitorHeight-1)
- monitor.setTextColor(colors.cyan)
- monitor.write("Song list")
- monitor.setCursorPos(monitorWidth-9, monitorHeight-1)
- if paused then
- monitor.write("Play ")
- else
- monitor.write("Pause ")
- end --if paused
- monitor.setTextColor(colors.blue)
- monitor.write("Skip")
- end --if full
- monitor.setCursorPos(1, monitorHeight)
- monitor.setTextColor(colors.lightGray)
- local minutes = math.floor(ticksPlayed*100/tempo/60)
- local seconds = math.floor(ticksPlayed*100/tempo) % 60
- if minutes < 10 then monitor.write(" ") end
- monitor.write(minutes..":")
- if seconds < 10 then monitor.write("0") end
- monitor.write(seconds.."")
- minutes = math.floor(songLength*100/tempo/60)
- seconds = math.floor(songLength*100/tempo) % 60
- monitor.setCursorPos(monitorWidth-4, monitorHeight)
- if minutes < 10 then monitor.write(" ") end
- monitor.write(minutes..":")
- if seconds < 10 then monitor.write("0") end
- monitor.write(seconds.."")
- monitor.setCursorPos(7, monitorHeight)
- monitor.write("<")
- for i = 8, monitorWidth-7 do
- monitor.write("=")
- end --for monitorWidth
- monitor.write(">")
- monitor.setTextColor(colors.white)
- end --displayCurrentlyPlaying()
- function header(song)
- local strLen = 0
- songLength = readNumber(song, 2)
- readNumber(song, 2) --song height
- strLen = readNumber(song, 4)
- songName = readString(song, strLen)
- strLen = readNumber(song, 4)
- songAuth = readString(song, strLen)
- strLen = readNumber(song, 4)
- origSongAuth = readString(song, strLen)
- strLen = readNumber(song, 4)
- songDesc = readString(song, strLen)
- local tempo = readNumber(song, 2)
- 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
- return tempo
- end --header()
- function playSong(number)
- while true do --coroutine loop
- if song ~= nil then song.close() end
- if number == 0 then number = nil end
- while number == nil do
- number = coroutine.yield()
- if number == 0 then number = nil end
- end -- while number == nil
- song = fs.open(musicList[number], "rb")
- if song == nil then
- print("File not found")
- break
- end --if nil
- tempo = header(song)
- ticksPlayed = -1
- local nextTick = 0
- local instrument = 0
- local key = 0
- local running = true
- while running do --song loop
- nextTick = readNumber(song, 2)
- -- if end of file
- if nextTick == 0 or nextTick == nil then
- instrum = {0, 0, 0, 0, 0}
- transmitNote()
- finished = true
- break
- end --if nextTick
- for tick = 1, nextTick do --wait for next note
- ticksPlayed = ticksPlayed + 1
- number = coroutine.yield()
- if number ~= nil then running = false break end
- end --for tick
- if number == nil then
- while readNumber(song, 2) ~= 0 do --play chord
- instrument = readNumber(song, 1)
- key = readNumber(song, 1)
- instrum[instrument+1] = bit.bor(instrum[instrument+1], bit.blshift(1, key-33))
- playNote(instrument, key-33)
- end --while chord
- transmitNote()
- instrum = {0, 0, 0, 0, 0}
- elseif number == 0 then --stop
- instrum = {0, 0, 0, 0, 0}
- transmitNote()
- end --if number
- end --while song loop
- --song = nil FIXME why was this here? - removed
- end --while coroutine loop
- end --playSong()
- function transmitNote()
- if modem == nil then return end
- for instrument = 1, 5 do
- modem.transmit(instrument, 0, instrum[instrument])
- end --for instrument
- end --transmitNote()
- function playNote(type, key)
- if noteblock == nil then return end
- if type == 0 then noteblock.playNote(0, key)
- elseif type == 1 then noteblock.playNote(4, key)
- elseif type == 2 then noteblock.playNote(1, key)
- elseif type == 3 then noteblock.playNote(2, key)
- else noteblock.playNote(3, key) end
- end
- displayMusicList(page)
- local play = coroutine.create(playSong)
- local arg = nil
- local event, side, x, y
- os.startTimer(0.1)
- while coroutine.status(play) ~= "dead" do
- event, side, x, y = os.pullEventRaw()
- if updateNeeded then
- updateNeeded = false
- if screen == 1 then
- displayMusicList(page, playing)
- elseif screen == 2 then
- displayCurrentlyPlaying(playing, true)
- end --if screen
- end --if update
- if event == "terminate" then
- monitor.clear()
- return
- end --if terminate
- if event == "timer" then
- os.startTimer(100/tempo)
- if finished then
- finished = false
- if repeatMode == "single" then
- arg = playing
- elseif repeatMode == "off" then
- screen = 1
- playing = nil
- tempo = 100 -- slow timer
- refreshCounter = 0
- else
- nextSong()
- arg = playing
- end -- if repeatMode
- if screen == 1 then
- displayMusicList(page, playing)
- elseif screen == 2 then
- displayCurrentlyPlaying(playing, true)
- end --if screen
- end -- if finished
- if refreshCounter <= 0 then
- refreshCounter = 100
- if screen == 1 then
- displayMusicList(page, playing)
- elseif screen == 2 then
- displayCurrentlyPlaying(playing, true)
- end -- if screen
- end -- if refreshCounter
- refreshCounter = refreshCounter - 1
- if not paused then
- if screen == 2 then
- displayCurrentlyPlaying(playing, false)
- end --if screen
- coroutine.resume(play, arg)
- elseif arg ~= nil then
- coroutine.resume(play, arg)
- end --if not paused
- end
- arg = nil
- if event == "monitor_touch" then
- if screen == 1 then
- if y > 1 and y < monitorHeight-1 then
- -- select song
- arg = (y-1)+(page-1)*(monitorHeight-3)
- playing = arg
- displayMusicList(page, playing)
- elseif y == monitorHeight-1 then
- if x >= monitorWidth-9 and x < monitorWidth-4 then
- paused = not paused
- updateNeeded = true
- elseif x >= monitorWidth-3 then
- nextSong()
- arg = playing
- displayMusicList(page, playing)
- coroutine.resume(play, arg)
- elseif x <= 17 then
- -- currently playing
- if playing ~= 0 and playing ~= nil then
- screen = 2
- displayCurrentlyPlaying(playing, true)
- end --if playing
- end --if monitorHeight-1
- elseif y == monitorHeight then
- -- previous, next
- if x < 9 then
- page = page - 1
- if page <= 0 then page = 1 end
- displayMusicList(page, playing)
- elseif x > monitorWidth-4 then
- if page*(monitorHeight-3) < #musicList then
- page = page + 1
- end --if page
- displayMusicList(page, playing)
- end --if x
- else --if y
- -- top line
- if x > monitorWidth-4 then
- -- stop
- arg = 0
- playing = arg
- displayMusicList(page, playing)
- elseif x > 16 and x <= monitorWidth-6 then
- 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"
- repeatMode = "off"
- end -- if repeatMode
- displayMusicList(page, playing)
- end --if x
- end --if y
- elseif screen == 2 then
- if y == monitorHeight-1 then
- if x >= monitorWidth-3 then
- nextSong()
- arg = playing
- displayCurrentlyPlaying(playing, true)
- coroutine.resume(play, arg)
- elseif x >= monitorWidth-9 and x < monitorWidth-4 then
- paused = not paused
- updateNeeded = true
- elseif x <= 9 then
- -- song list
- screen = 1
- displayMusicList(page, playing)
- end --if x
- elseif y == 1 then
- if x > monitorWidth-4 then
- -- stop
- arg = 0
- playing = arg
- screen = 1
- displayMusicList(page, playing)
- elseif x > 16 and x <= monitorWidth-6 then
- 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"
- repeatMode = "off"
- end -- if repeatMode
- displayCurrentlyPlaying(playing, true)
- end
- end --if y
- end --if screen == 1
- end --monitor touch
- if event == "peripheral" or event == "peripheral_detach" or event == "monitor_resize" then
- modem = peripheral.find("modem")
- monitor = peripheral.find("monitor")
- if monitor == nil then
- term.setTextColor(colors.red)
- print("Error: monitor detached")
- return
- end
- noteblock = peripheral.find("iron_noteblock")
- monitorWidth, monitorHeight = monitor.getSize()
- if screen == 1 then
- displayMusicList(page, playing)
- elseif screen == 2 then
- displayCurrentlyPlaying(playing, true)
- end
- end --if peripheral
- if event == "disk" then
- refreshMusicList()
- updateNeeded = true
- end --if disk
- if event == "disk_eject" then
- if playing ~= 0 and playing ~= nil then
- local length = #musicList
- local thisSong = musicList[playing]
- if string.sub(thisSong, 0, 4) == "disk" then
- if string.sub(thisSong, 5, 5) == "/" then
- if not fs.isDir("disk") then
- arg = 0
- end --if isDir
- else
- if not fs.isDir("disk"..string.sub(thisSong, 5, 5)) then
- arg = 0
- end --if isDir
- end --if "/"
- end --if playing disk
- refreshMusicList()
- updateNeeded = true
- if arg == 0 then
- playing = arg
- if screen == 2 then
- screen = 1
- end
- coroutine.resume(play, arg)
- end --if arg
- else --if playing
- refreshMusicList()
- updateNeeded = true
- end --if playing
- end -- if disk_eject
- end --while coroutine
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement