Advertisement
Guest User

Untitled

a guest
Mar 18th, 2019
247
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 5.83 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("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