Advertisement
TxN

nbs music player

TxN
Apr 18th, 2016
613
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Lua 5.82 KB | None | 0 0
  1.  
  2.  
  3. --[[
  4.    nbs music player
  5.    Простая программка для проигрывания музыки формата nbs, использующая музыкальные блоки из Computronics.
  6.    Музыку и редактор для нее можно найти, загуглив Minecraft Note Block Studio.
  7.  
  8.    Для использования подключите к компьютеру кабелем железные музыкальные блоки. Рекомендуемое количество - 8, можно больше или меньше.
  9.  
  10.    TxN, 2016  
  11. ]]
  12.  
  13. local component = require("component")
  14. local fs = require("filesystem")
  15. local shell = require("shell")
  16. local computer = require("computer")
  17.  
  18. local players_list = {}
  19.  
  20. local song = {}
  21.  
  22. player = {}
  23.  
  24. function player.upd(self)
  25.     curtime = computer.uptime()
  26.     if curtime >= self.next_tick_time then
  27.         -- Достаем информацию о нотах из текущего тика, настраиваем музыкальные блоки
  28.         self.block_position = song:set_tick(players_list, self.current_tick, self.block_position)
  29.  
  30.         -- Играем аккорд
  31.         players_list:play_chord()
  32.         players_list:clear_players()
  33.         -- Инкрементим тик
  34.         self.current_tick = self.current_tick + 1
  35.         self.next_tick_time  = curtime + 1/song.tempo
  36.        
  37.         if self.current_tick == song.length then
  38.            self.play_complete = true
  39.         end
  40.     end
  41. end
  42.  
  43.  
  44. function get_players()
  45.   local i = 1
  46.   for k,v in pairs(component.list("iron_noteblock")) do
  47.     local pl = {}
  48.     pl.index = i
  49.     pl.instrument = 0
  50.     pl.note = 0
  51.     pl.interface =  component.proxy(k)
  52.     pl.busy = false
  53.     table.insert(players_list,pl)
  54.     i = i + 1
  55.   end
  56. end
  57.  
  58. function set_player(player,instr, nt)
  59.    player.instrument = instr
  60.    player.note = nt
  61.    player.busy = true
  62. end
  63.  
  64. function players_list:get_free_player()
  65.     for k,v in pairs (self) do
  66.       if v.busy == false then
  67.           return v
  68.       end
  69.     end
  70.    
  71.     return nil
  72. end
  73.  
  74. function players_list:clear_players()
  75.     for k,v in pairs (self) do
  76.       if (type(v) == "table") then
  77.         v.busy = false
  78.         v.instrument = 0
  79.         v.note = 0
  80.       end
  81.     end  
  82. end
  83.  
  84. function players_list:play_chord()
  85.     for k,v in pairs (self) do
  86.       if (type(v) == "table") then
  87.         if v.busy == true then
  88.            v.interface.playNote(v.instrument, v.note)
  89.         end
  90.       end
  91.     end  
  92. end
  93.  
  94. function song:loadSong(path)
  95.     --Кинуть ошибку, если такого файла не существует
  96.     if not fs.exists(path) then error("File \""..path.."\" does not exist.\n") end
  97.     local file = io.open(path, "rb")
  98.     self.length = get_int_16(getByte(file),getByte(file))
  99.    
  100.     self.height = get_int_16(getByte(file),getByte(file))
  101.     self.name = readString(file)
  102.     self.author = readString(file)
  103.     self.org_author = readString(file)
  104.     self.description = readString(file)
  105.    
  106.     self.tempo =  get_int_16(getByte(file),getByte(file))
  107.     self.tempo = self.tempo * 0.01
  108.     local tmp = file:read(23) -- тут ненужная информация, ну совсем ненужная
  109.     tmp = readString(file) -- тут тоже, но это строка вдобавок
  110.    
  111.     print(self.name)
  112.     print(self.description)
  113.     print("Length in ticks: "..self.length)
  114.    
  115.     self.song_ticks = {}
  116.    
  117.     local tick = -1
  118.     local jumps = 0
  119.    
  120.     local counter = 1
  121.     while (true) do
  122.      
  123.       jumps = get_int_16(getByte(file),getByte(file))
  124.       if jumps == 0 then
  125.         break
  126.       end
  127.      
  128.       tick = tick + jumps
  129.       local layer = -1
  130.      
  131.      
  132.       while (true) do
  133.         self.song_ticks[counter] = {}
  134.         jumps = get_int_16(getByte(file),getByte(file))
  135.         if jumps == 0 then
  136.           break
  137.         end
  138.         layer = layer + jumps
  139.         self.song_ticks[counter].instrument = getByte(file)
  140.         self.song_ticks[counter].note = getByte(file) - 33
  141.         self.song_ticks[counter].layer = layer
  142.         self.song_ticks[counter].tick = tick
  143.         counter = counter + 1
  144.       end
  145.     end
  146.    
  147.     self.blocks_num = counter -1
  148.    
  149.     print("Load complete") 
  150.     file:close()
  151. end
  152.  
  153.  
  154. function song:set_tick(players, cur_tick, position)
  155.     while (true) do
  156.      if self.song_ticks[position].tick == cur_tick then
  157.        freeplayer = players:get_free_player()
  158.        if (freeplayer ~= nil) then
  159.          set_player(freeplayer,self.song_ticks[position].instrument,self.song_ticks[position].note)
  160.        end
  161.        position = position + 1
  162.      else
  163.        break
  164.      end
  165.     end
  166.    
  167.     return position
  168. end
  169.  
  170. function getByte(f)
  171.   return string.byte(f:read(1))
  172. end
  173.  
  174. function readString(file)
  175.   local strln = get_int_32(getByte(file),getByte(file),getByte(file),getByte(file))
  176.   local str = ""
  177.   str = file:read(strln)
  178.   return str
  179.  end
  180.  
  181. function get_int_16(b1, b2)
  182.     local n = b1 + 256 * b2
  183.     n = (n > 32767) and (n - 32768) or n
  184.     return n
  185. end  
  186.  
  187. function get_int_32(b1, b2, b3, b4)
  188.       if not b4 then error("need four bytes to convert to int",2) end
  189.       local n = b1 + b2*256 + b3*65536 + b4*16777216
  190.       n = (n > 2147483647) and (n - 4294967296) or n
  191.       return n
  192. end
  193.  
  194.  
  195. function player:init(songPath)
  196. -- находим подключенные к компьютеру музыкальные блоки
  197.     get_players()
  198. -- Задаем начальные параметры
  199.     self.play_complete = false
  200.     self.current_tick = 0
  201.     self.block_position = 1
  202.     self.next_tick_time = computer.uptime()
  203.     -- Загружаем песню из файла
  204.     song:loadSong(songPath)
  205. end
  206.  
  207.  
  208. --------
  209. -- Тут собственно точка входа программы
  210. --------
  211.  
  212. local args = shell.parse(...)
  213. if #args == 0 then
  214.   io.write("Usage: musicPlayer <path_to_song_file>\n")
  215.   return 1
  216. end
  217.  
  218. local path = args[1]
  219.  
  220. player:init(path)
  221.  
  222. --Играем песню пока не кончится
  223. while not player.play_complete do
  224.     player.upd(player)
  225.     os.sleep(0.01)
  226. end
  227. print("Song played successfully")
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement