Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- -- Musikcomputer.lua
- -- CC:Tweaked Musiksystem (mit BPM, Filterung & synchronisiertem Start)
- -- Version 2.0
- local CONFIG_FILE = "config.txt"
- local CONTROL_FILE = "disk/control.txt"
- local SONG_PATH_PREFIX = "disk/song_"
- local instrumentConfig = {}
- -- -----------------------------
- -- Hilfsfunktionen
- -- -----------------------------
- local function fileExists(path)
- local f = fs.open(path, "r")
- if f then f.close() return true else return false end
- end
- local function saveConfig(config)
- local f = fs.open(CONFIG_FILE, "w")
- for k, v in pairs(config) do
- f.writeLine(k .. "=" .. v)
- end
- f.close()
- end
- local function loadConfig()
- local config = {}
- local f = fs.open(CONFIG_FILE, "r")
- if not f then return nil end
- for line in f.readLine do
- local key, value = line:match("^(.-)=(.*)$")
- if key and value then
- config[key] = value
- end
- end
- f.close()
- return config
- end
- -- -----------------------------
- -- Initialisierung
- -- -----------------------------
- local function initialize()
- print("Keine Konfiguration gefunden. Initialisierung startet...")
- local config = {}
- write("Instrumentname: ")
- config.name = read()
- local sides = {"front", "right", "back", "left"}
- for _, side in ipairs(sides) do
- write("Ton an Seite '" .. side .. "' (z.B. C#2 oder none): ")
- config[side] = read()
- end
- saveConfig(config)
- print("Konfiguration gespeichert.")
- return config
- end
- -- -----------------------------
- -- Lied laden (inkl. BPM)
- -- -----------------------------
- local function loadSong(instrumentName)
- local songPath = SONG_PATH_PREFIX .. instrumentName .. ".txt"
- if not fs.exists(songPath) then
- error("Songdatei nicht gefunden: " .. songPath)
- end
- local f = fs.open(songPath, "r")
- local bpm = 120
- local notes = {}
- while true do
- local line = f.readLine()
- if not line then break end
- if line:match("^BPM=") then
- bpm = tonumber(line:match("BPM=(%d+)"))
- elseif not (line:match("^#") or line == "") then
- local tonePart, length = line:match("^(.-)|(%d+)$")
- if tonePart and length then
- local tones = {}
- for tone in string.gmatch(tonePart, "([^,]+)") do
- table.insert(tones, tone)
- end
- table.insert(notes, {tones = tones, length = tonumber(length)})
- end
- end
- end
- f.close()
- return bpm, notes
- end
- -- -----------------------------
- -- Filter nach bespielbaren Noten
- -- -----------------------------
- local function filterSong(song, config, bpm)
- local playable = {}
- local sideNotes = {}
- for _, side in ipairs({"front", "right", "back", "left"}) do
- if config[side] and config[side] ~= "none" then
- sideNotes[config[side]] = side
- end
- end
- local function noteLengthToSeconds(noteValue, bpm)
- return (4 / noteValue) * (60 / bpm)
- end
- for _, entry in ipairs(song) do
- local validTones = {}
- for _, tone in ipairs(entry.tones) do
- if sideNotes[tone] then
- table.insert(validTones, tone)
- end
- end
- if #validTones > 0 then
- table.insert(playable, {
- tones = validTones,
- length = noteLengthToSeconds(entry.length, bpm)
- })
- else
- table.insert(playable, {
- tones = {"REST"},
- length = noteLengthToSeconds(entry.length, bpm)
- })
- end
- end
- return playable, sideNotes
- end
- -- -----------------------------
- -- Steuerdatei lesen
- -- -----------------------------
- local function readControlFile()
- if not fileExists(CONTROL_FILE) then return false, 0 end
- local f = fs.open(CONTROL_FILE, "r")
- local play = false
- local startTime = 0
- while true do
- local line = f.readLine()
- if not line then break end
- local key, val = line:match("^(.-)=(.*)$")
- if key == "play" then
- play = (val == "true")
- elseif key == "startTime" then
- startTime = tonumber(val)
- end
- end
- f.close()
- return play, startTime
- end
- -- -----------------------------
- -- Song abspielen
- -- -----------------------------
- local function playSong(filtered, sideNotes)
- for _, entry in ipairs(filtered) do
- if entry.tones[1] == "REST" then
- sleep(entry.length)
- else
- -- Redstone aktivieren
- for _, tone in ipairs(entry.tones) do
- local side = sideNotes[tone]
- if side then redstone.setOutput(side, true) end
- end
- sleep(0.001)
- -- Redstone deaktivieren
- for _, tone in ipairs(entry.tones) do
- local side = sideNotes[tone]
- if side then redstone.setOutput(side, false) end
- end
- -- Rest der Notenlänge warten
- local remaining = entry.length - 0.001
- if remaining > 0 then sleep(remaining) end
- end
- end
- end
- -- -----------------------------
- -- Hauptprogramm
- -- -----------------------------
- if fileExists(CONFIG_FILE) then
- instrumentConfig = loadConfig()
- print("Konfiguration geladen für Instrument: " .. instrumentConfig.name)
- else
- instrumentConfig = initialize()
- end
- print("Lade Song von Disk...")
- local bpm, song = loadSong(instrumentConfig.name)
- print("Song geladen (" .. #song .. " Schritte) mit BPM = " .. bpm)
- print("Filtere Song für bespielbare Noten...")
- local filtered, sideNotes = filterSong(song, instrumentConfig, bpm)
- print("Gefilterter Song enthält " .. #filtered .. " Einträge.")
- print("Warte auf Startsignal...")
- while true do
- local play, startTime = readControlFile()
- if play then
- local current = os.epoch("utc")
- local diff = startTime - current
- if diff > 0 then
- print("Starte Song in " .. string.format("%.2f", diff / 1000) .. " Sekunden...")
- sleep(diff / 1000)
- end
- print("Starte Abspielen!")
- playSong(filtered, sideNotes)
- print("Song beendet.")
- break
- end
- sleep(0.2) -- Systemschonende Abfrage
- end
Advertisement
Add Comment
Please, Sign In to add comment