daily pastebin goal
80%
SHARE
TWEET

nbsplay.lua

a guest Jan 18th, 2019 77 Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  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")
RAW Paste Data
We use cookies for various purposes including analytics. By continuing to use Pastebin, you agree to our use of cookies as described in the Cookies Policy. OK, I Understand
 
Top