Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- local dfpwm = require("cc.audio.dfpwm")
- local speakers = { peripheral.find("speaker") } -- this way i can utilyze ALL speakers
- -- Initial Boot Setup Script
- local basaltExists = fs.exists("basalt.lua")
- local musicDir = "/disk/"
- local configFilePath = "/config.txt"
- local defaultConfig = {
- chunkSize = 1024*6, -- Default chunk size
- }
- local function downloadAndRunInstaller(url, ...)
- local args = {...} -- Capture any additional arguments to pass to the script
- -- Use http.get to fetch the script
- local response = http.get(url)
- if not response then
- error("Failed to download the installer script")
- end
- local scriptContent = response.readAll()
- response.close()
- -- Use loadstring to load the script content.
- -- Note: loadstring is available in Lua 5.1, but in newer versions, load may be used.
- local script, errorMessage = loadstring(scriptContent)
- if not script then
- error("Failed to load the installer script: " .. errorMessage)
- end
- -- Execute the loaded script, passing any additional arguments
- script(table.unpack(args))
- end
- -- Function to check and install Basalt
- local function installBasalt()
- if not basaltExists then
- print("Basalt not found. Attempting to download...")
- downloadAndRunInstaller("https://basalt.madefor.cc/install.lua", "release", "latest.lua")
- print("Basalt installed successfully.")
- else
- print("Basalt is already installed.")
- end
- end
- -- Function to create the music directory if it doesn't exist
- local function createMusicDirectory()
- if not fs.exists(musicDir) then
- print("Missing Disk. Please, insert Disk and Restart.")
- os.pullEventRaw("terminate")
- else
- print("Disk detected")
- end
- end
- -- Function to create or update the configuration file
- local function createOrUpdateConfig()
- local configData = textutils.serialize(defaultConfig)
- local configFile = fs.open(configFilePath, "w")
- configFile.write(configData)
- configFile.close()
- print("Configuration file created/updated.")
- end
- -- Main function to run the initial setup
- local function runInitialSetup()
- installBasalt()
- createMusicDirectory()
- createOrUpdateConfig()
- if basaltExists == false then
- term.clear()
- print("Initial setup completed.")
- print("Program is terminating to allow user upload of music.")
- print("Use the /music/ folder created for music storage.")
- print("Sub folders are supported to allow for user organization")
- print("Thank you for using this program and enjoy!")
- print()
- print("-coppertj")
- os.sleep(5)
- error()
- end
- end
- -- Execute the initial setup
- runInitialSetup()
- -- Ensure these are initialized at the start of your script
- local basalt = require("basalt")
- local isPaused = false
- local lastChunkData = nil
- local currentPosition = 1
- local playbackStarted = false
- local trackStartTime = 0
- local backPressedOnce = false
- local basalt = require("basalt")
- local breakit = false
- local main = basalt.createFrame()
- local screenWidth, screenHeight = main:getSize()
- local numBars = 16 -- Number of bars in the visualizer
- local barWidth = 1 -- Width of each bar (1 character)
- local visualizerHeight = 10 -- Max height of the visualizer
- local visualizerStartX = math.floor((screenWidth - (numBars * barWidth)) / 2)
- local visualizerStartY = screenHeight - visualizerHeight - 5 -- Position above the bottom buttons
- local buttonWidth = screenWidth / 4
- local buttonHeight = 3 -- Height of buttons
- local spacing = (screenWidth - (buttonWidth * 3)) / 4
- local startY = screenHeight - buttonHeight - 1 -- Y position for buttons
- local returnToMenu = false
- -- Define rootFolder where your music files are located
- local rootFolder = "/disk/"
- local shuffleEnabled = false
- -- Function to read the contents of a folder and return the filenames as a table
- function readFolderContents(folderPath)
- local fileNames = {}
- for _, file in ipairs(fs.list(folderPath)) do
- table.insert(fileNames, file)
- end
- return fileNames
- end
- -- This is the function that i took from someone elses code
- function playChunk(chunk)
- local returnValue = nil
- local callbacks = {}
- for i, speaker in pairs(speakers) do
- if i > 1 then
- table.insert(callbacks, function()
- speaker.playAudio(chunk, volume or 1.0)
- end)
- else
- table.insert(callbacks, function()
- returnValue = speaker.playAudio(chunk, volume or 1.0)
- end)
- end
- end
- parallel.waitForAll(table.unpack(callbacks))
- return returnValue
- end
- -- Shuffle State Label
- local shuffleStateLabel = main:addLabel()
- :setText("Shuffle: Off")
- :setPosition(12, 2) -- Adjust to position next to the shuffle button
- :setSize(15, 1)
- local function updateShuffleStateLabel()
- if shuffleEnabled then
- shuffleStateLabel:setText("Shuffle: On")
- else
- shuffleStateLabel:setText("Shuffle: Off")
- end
- -- Refresh the frame to show the updated label text if necessary
- end
- local function onShufflePressed()
- shuffleEnabled = not shuffleEnabled
- updateShuffleStateLabel()
- end
- -- Assuming you have variables for spacing and startY like before
- -- Adjust these values as needed to position your shuffle button
- local shuffleButtonX = 10 -- Adjust based on your layout, for example, placing it at the top left
- local shuffleButtonY = 20 -- Adjust based on your layout, perhaps just below the top edge
- -- Initialize fileList using the readFolderContents function
- -- File Explorer
- local mainFrame = basalt.createFrame("firstBaseFrame"):show()
- local fileList = mainFrame:addList()
- :setPosition(2, 2)
- :setSize(20, 15) -- Adjust size as needed
- local function updateFileList(path)
- fileList:clear() -- Clear the list for new directory contents
- local files = fs.list(path) -- Use the passed 'path' parameter
- for _, file in ipairs(files) do
- fileList:addItem(file) -- Add each file or directory to the list
- end
- end
- fileList:onSelect(function(self, event, item)
- if item and item.text then
- local selectedFileName = item.text
- local selectedItemPath = fs.combine(rootFolder, selectedFileName)
- if fs.isDir(selectedItemPath) then
- -- Navigate into the directory
- rootFolder = selectedItemPath .. "/" -- Update the rootFolder to the new path
- updateFileList(rootFolder) -- Update the list to show contents of the selected directory
- else
- -- Handle file selection
- basalt.setActiveFrame(main) -- Switch to the playback frame
- parallel.waitForAny(
- function() mainLoop(selectedItemPath) end, -- Play the selected file
- waitForUserInput -- Continue listening for user input
- )
- end
- end
- end)
- -- Add any additional UI elements like a back button here
- local function togglePauseState()
- isPaused = not isPaused
- end
- local function onPlaybackPressed()
- local currentTime = os.clock()
- if backPressedOnce and (currentTime - trackStartTime) <= 3 then
- -- If back button is pressed twice within 3 seconds, go to the previous song
- currentPosition = math.max(1, currentPosition - 1)
- backPressedOnce = false -- Reset the flag
- else
- -- If pressed once or after 3 seconds, restart the current song or go to the previous song
- if (currentTime - trackStartTime) > 3 then
- -- Consider as a request to go back if beyond the threshold
- currentPosition = math.max(1, currentPosition - 1)
- end
- backPressedOnce = true -- Set the flag for the first press
- trackStartTime = currentTime -- Update start time to prevent immediate trigger
- end
- breakit = true
- -- Exit to restart the current song or go to the previous song
- end
- local playedTracks = {}
- local fileLister = readFolderContents(rootFolder)
- function shuffleTrack()
- -- Reset shuffle if all tracks have been played
- if tablelength(playedTracks) >= #fileLister then
- playedTracks = {} -- Clear played tracks for reshuffle
- -- Optional: Return to the menu or start shuffle again
- end
- local nextTrack
- repeat
- nextTrack = math.random(1, #fileLister)
- until not playedTracks[nextTrack]
- playedTracks[nextTrack] = true
- currentPosition = nextTrack -- Update current position for shuffle track
- return true
- end
- local function onSkipPressed()
- -- If shuffle is not enabled, simply move to the next track in order
- if currentPosition > #fileLister then
- currentPosition = 1 -- Optionally loop back to the start or stop playback
- end
- breakit = true
- end
- local bars = {}
- for i = 1, numBars do
- local xPosition = visualizerStartX + (i - 1) * barWidth
- bars[i] = main:addLabel()
- :setPosition(xPosition, visualizerStartY)
- :setSize(barWidth, visualizerHeight)
- :setText("|")
- end
- local labelYPosition = visualizerStartY + 7 -- Position the label above the visualizer, adjust as needed
- local trackLabel = main:addLabel()
- :setPosition(1, labelYPosition)
- :setSize(screenWidth, 5)
- :setText("")
- local function onMainMenuButtonPressed()
- breakit = true
- returnToMenu = true
- rootFolder = "/disk/"
- updateFileList(rootFolder)
- basalt.setActiveFrame(mainFrame)
- mainFrame:show()
- main:hide()
- basalt.update()
- -- Initialize the list with contents from the starting directory
- end
- function waitForUserInput()
- breakit = false
- returnToMenu = false
- basalt.setActiveFrame(main)
- main:show()
- mainFrame:hide()
- basalt.update()
- while true do
- if returnToMenu == true then
- basalt.setActiveFrame(mainFrame)
- main:show()
- mainFrame:hide()
- basalt.update()
- -- Initialize the list with contents from the starting directory
- break
- end
- -- Creating buttons
- -- Create the main menu button at the top left corner of the screen
- local mainMenuButton = main:addButton()
- :setText("=")
- :setPosition(1, 1) -- Top left corner
- :setSize(3, 1) -- Adjust size as needed
- :onClick(onMainMenuButtonPressed)
- -- Create the shuffle button with a smaller size
- local shuffleButton = main:addButton()
- :setText("Shuffle")
- :setPosition(shuffleButtonX, shuffleButtonY)
- :setSize(7, 1) -- Smaller width and standard height for a single character
- :onClick(onShufflePressed)
- -- Playback Button
- local playbackButton = main:addButton()
- :setText("<")
- :setPosition(spacing * 2, startY)
- :setSize(buttonWidth, buttonHeight)
- :onClick(onPlaybackPressed)
- -- Pause Button
- local pauseButton = main:addButton()
- :setText("||")
- :setPosition(spacing * 3 + buttonWidth, startY)
- :setSize(buttonWidth, buttonHeight)
- :onClick(togglePauseState)
- -- Skip Button
- local skipButton = main:addButton()
- :setText(">")
- :setPosition(spacing * 4 + buttonWidth * 2, startY)
- :setSize(buttonWidth, buttonHeight)
- :onClick(onSkipPressed)
- for i = 1, numBars do
- local height
- if isPaused then
- height = 1 -- Set height to 0 to clear the bars if paused
- else
- height = math.random(1, visualizerHeight) -- Otherwise, set a random height
- end
- local barText = string.rep("|", height) .. string.rep(" ", visualizerHeight - height)
- bars[i]:setText(barText)
- end
- local ev = table.pack(os.pullEventRaw())
- basalt.update(table.unpack(ev))
- end
- end
- local function updateShuffleStateLabel()
- if shuffleEnabled then
- shuffleStateLabel:setText("Shuffle: On")
- else
- shuffleStateLabel:setText("Shuffle: Off")
- end
- -- Refresh the frame to show the updated label text if necessary
- end
- -- Updated function to play a DFPWM file, incorporating pause logic
- function playSound(filePath)
- breakit = false
- trackStartTime = os.clock()
- local file = fs.open(filePath, "rb")
- if not file then
- return
- end
- local decoder = dfpwm.make_decoder()
- local chunkData, buffer
- local fileName = filePath:match("^.+/(.+)$") or filePath -- Pattern extracts the name after the last slash
- trackLabel:setText(fileName) -- Update the label text with the current file name
- while true do
- if breakit == true then break end
- if isPaused then
- os.sleep(0.5) -- Simple pause handling
- else
- chunkData = file.read(1024*16)
- if not chunkData then break end -- End of file
- buffer = decoder(chunkData)
- while not playChunk(buffer) do
- if isPaused then
- lastChunkData = chunkData -- Save the chunk data if paused mid-playback
- break
- end
- os.pullEvent("speaker_audio_empty")
- end
- end
- end
- file.close()
- end
- -- Main playback loop
- -- Initialize playedTracks outside the main loop to track played files across shuffle iterations
- local playedTracks = {}
- -- Main playback loop
- function mainLoop(initialTrackPath)
- fileLister = readFolderContents(rootFolder)
- if initialTrackPath then
- -- Directly play the provided track
- playSound(initialTrackPath)
- -- Find and set currentPosition for the next track
- for index, fileName in ipairs(fileLister) do
- local filePath = fs.combine(rootFolder, fileName)
- if filePath == initialTrackPath then
- currentPosition = index + 1
- break
- end
- end
- end
- -- Check if shuffle is enabled and reset playedTracks if necessary
- if shuffleEnabled and #playedTracks == #fileLister then
- playedTracks = {} -- Reset after all tracks have been played
- end
- while currentPosition <= #fileLister do
- if returnToMenu then break end
- local fileName = fileLister[currentPosition]
- local filePath = fs.combine(rootFolder, fileName) -- Correctly combine paths
- if shuffleEnabled then
- local nextTrack
- repeat
- nextTrack = math.random(1, #fileLister)
- until not playedTracks[nextTrack] or #playedTracks == #fileLister
- playedTracks[nextTrack] = true
- currentPosition = nextTrack
- filePath = fs.combine(rootFolder, fileLister[currentPosition]) -- Update filePath for shuffle
- playSound(filePath)
- else
- playSound(filePath)
- currentPosition = currentPosition + 1
- end
- if currentPosition > #fileLister and not shuffleEnabled then
- breakit = true
- returnToMenu = true
- basalt.setActiveFrame(mainFrame)
- mainFrame:show()
- main:hide()
- basalt.update()
- -- Initialize the list with contents from the starting directory
- updateFileList("/disk/")
- break
- end
- end
- end
- updateFileList(rootFolder)
- basalt.autoUpdate()
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement