Advertisement
Guest User

nbsplay.lua

a guest
Jan 18th, 2019
107
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Lua 5.40 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("note")) do
  23.     local pl = {}
  24.   pl.index = i
  25.   pl.note = 0
  26.   pl.interface =  component.proxy(k)
  27.   pl.busy = false
  28.     table.insert(players_list,pl)
  29.   i = i + 1
  30.   end
  31. end
  32.  
  33. function set_player(player, nt)
  34.   while nt < 1 do nt = nt + 12 end
  35.   while nt > 25 do nt = nt - 12 end
  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.note = 0
  55.     end
  56.   end  
  57. end
  58.  
  59. function players_list:play_chord()
  60.     for k,v in pairs (self) do
  61.     if (type(v) == "table") then
  62.       if v.busy == true then
  63.         v.interface.setPitch(v.note)
  64.         v.interface.trigger()
  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].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) or 'a')
  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