Advertisement
TxN

Minecraft NBS Music player for OpenComputers

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