Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- --[[
- nbs music player
- Простая программка для проигрывания музыки формата nbs, использующая музыкальные блоки из Computronics.
- Музыку и редактор для нее можно найти, загуглив Minecraft Note Block Studio.
- Для использования подключите к компьютеру кабелем железные музыкальные блоки. Рекомендуемое количество - 8, можно больше или меньше.
- TxN, 2016
- ]]
- local component = require("component")
- local fs = require("filesystem")
- local shell = require("shell")
- local computer = require("computer")
- local speedoverride = 1
- local players_list = {}
- local song = {}
- local NBS_MC_inst = {
- [1] = 0,
- [2] = 4,
- [3] = 1,
- [4] = 2,
- [5] = 3,
- [6] = 5,
- [7] = 6
- }
- player = {}
- function player.upd(self)
- --curtime = computer.uptime()
- curtime = os.time() / 60
- if curtime >= self.next_tick_time then
- -- Достаем информацию о нотах из текущего тика, настраиваем музыкальные блоки
- self.block_position = song:set_tick(players_list, self.current_tick, self.block_position)
- -- Играем аккорд
- players_list:play_chord()
- players_list:clear_players()
- -- Инкрементим тик
- self.current_tick = self.current_tick + 1
- self.next_tick_time = curtime + 1/song.tempo/speedoverride
- if self.current_tick == song.length then
- self.play_complete = true
- end
- end
- end
- function get_players()
- local i = 1
- for k,v in pairs(component.list("iron_noteblock")) do
- local pl = {}
- pl.index = i
- pl.instrument = 0
- pl.note = 0
- pl.interface = component.proxy(k)
- pl.busy = false
- table.insert(players_list,pl)
- i = i + 1
- end
- end
- function set_player(player,instr, nt)
- player.instrument = instr
- player.note = nt
- player.busy = true
- end
- function players_list:get_free_player()
- for k,v in pairs (self) do
- if v.busy == false then
- return v
- end
- end
- return nil
- end
- function players_list:clear_players()
- for k,v in pairs (self) do
- if (type(v) == "table") then
- v.busy = false
- v.instrument = 0
- v.note = 0
- end
- end
- end
- function players_list:play_chord()
- for k,v in pairs (self) do
- if (type(v) == "table") then
- if v.busy == true then
- v.interface.playNote(v.instrument, v.note)
- end
- end
- end
- end
- function song:loadSong(path)
- --Кинуть ошибку, если такого файла не существует
- if not fs.exists(path) then error("File \""..path.."\" does not exist.\n") end
- local file = io.open(path, "rb")
- self.length = get_int_16(getByte(file),getByte(file))
- self.height = get_int_16(getByte(file),getByte(file))
- self.name = readString(file)
- self.author = readString(file)
- self.org_author = readString(file)
- self.description = readString(file)
- self.tempo = get_int_16(getByte(file),getByte(file))
- self.tempo = self.tempo * 0.01
- local tmp = file:read(23) -- тут ненужная информация, ну совсем ненужная
- tmp = readString(file) -- тут тоже, но это строка вдобавок
- print(self.name)
- print(self.description)
- print("Length in ticks: "..self.length)
- self.song_ticks = {}
- local tick = -1
- local jumps = 0
- local counter = 1
- while (true) do
- jumps = get_int_16(getByte(file),getByte(file))
- if jumps == 0 then
- break
- end
- tick = tick + jumps
- local layer = -1
- while (true) do
- self.song_ticks[counter] = {}
- jumps = get_int_16(getByte(file),getByte(file))
- if jumps == 0 then
- break
- end
- layer = layer + jumps
- self.song_ticks[counter].instrument = NBS_MC_inst[getByte(file)+1]
- --if(self.song_ticks[counter].instrument==1) then
- -- self.song_ticks[counter].instrument=4
- --end
- self.song_ticks[counter].note = getByte(file) - 33
- self.song_ticks[counter].layer = layer
- self.song_ticks[counter].tick = tick
- counter = counter + 1
- end
- end
- self.blocks_num = counter -1
- print("Load complete")
- file:close()
- end
- function song:set_tick(players, cur_tick, position)
- while (true) do
- if self.song_ticks[position].tick == cur_tick then
- freeplayer = players:get_free_player()
- if (freeplayer ~= nil) then
- set_player(freeplayer,self.song_ticks[position].instrument,self.song_ticks[position].note)
- end
- position = position + 1
- else
- break
- end
- end
- return position
- end
- function getByte(f)
- return string.byte(f:read(1))
- end
- function readString(file)
- local strln = get_int_32(getByte(file),getByte(file),getByte(file),getByte(file))
- local str = ""
- str = file:read(strln)
- return str
- end
- function get_int_16(b1, b2)
- local n = b1 + 256 * b2
- n = (n > 32767) and (n - 32768) or n
- return n
- end
- function get_int_32(b1, b2, b3, b4)
- if not b4 then error("need four bytes to convert to int",2) end
- local n = b1 + b2*256 + b3*65536 + b4*16777216
- n = (n > 2147483647) and (n - 4294967296) or n
- return n
- end
- function player:init(songPath)
- -- находим подключенные к компьютеру музыкальные блоки
- get_players()
- -- Задаем начальные параметры
- self.play_complete = false
- self.current_tick = 0
- self.block_position = 1
- self.next_tick_time = computer.uptime()
- -- Загружаем песню из файла
- song:loadSong(songPath)
- end
- --------
- -- Тут собственно точка входа программы
- --------
- local args = shell.parse(...)
- if #args == 0 then
- io.write("Usage: musicPlayer <path_to_song_file>\n")
- return 1
- end
- if args[2] then
- speedoverride=tonumber(args[2])
- print(speedoverride)
- end
- local path = args[1]
- player:init(path)
- --Играем песню пока не кончится
- while not player.play_complete do
- player.upd(player)
- os.sleep(0.0001)
- end
- print("Song played successfully")
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement