Advertisement
Guest User

Memdia player

a guest
Jan 21st, 2020
80
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 11.17 KB | None | 0 0
  1. local songBpm = 240
  2. local songLength = 1
  3. local songCursor = 1
  4. local songBeats = 0
  5.  
  6. local sp = {}
  7. local _i = 0
  8. for i=0, 50 do
  9. local p = peripheral.wrap("speaker_"..i)
  10. if (p ~= nil) then
  11. sp[_i] = p
  12. _i = _i+1
  13. end
  14. end
  15.  
  16. local nextSpeaker = 0
  17. local speakerCount = table.getn(sp)
  18.  
  19. local instrumentCount = 11
  20. local instruments = {
  21. -- musical
  22. {["name"] = "piano", ["file"] = "block.note.harp"},
  23. {["name"] = "bass", ["file"] = "block.note.bass"},
  24. {["name"] = "bell", ["file"] = "block.note.bell"},
  25. {["name"] = "chime", ["file"] = "block.note.chime"},
  26. {["name"] = "xhylophone", ["file"] = "block.note.xylophone"},
  27. {["name"] = "flute", ["file"] = "block.note.flute"},
  28. {["name"] = "guitar", ["file"] = "block.note.guitar"},
  29. {["name"] = "kick", ["file"] = "block.note.basedrum"},
  30. {["name"] = "hat", ["file"] = "block.note.hat"},
  31. {["name"] = "cimbal", ["file"] = "block.sand.break"},
  32. {["name"] = "snare", ["file"] = "block.note.snare"},
  33. -- sfx
  34. {["name"] = "levelup", ["file"] ="entity.player.levelup"}
  35. }
  36.  
  37. local song = {}
  38. local patterns = {}
  39.  
  40. local currentPattern = 1
  41. local currentSongPattern = 1
  42. local cursor = 1
  43. local playing = false
  44.  
  45. local playingTimer = nil
  46. local delayedNoteTimer = nil
  47. local delayedAllChannels = false
  48. local delayTime = 1
  49.  
  50. local progressTimer = nil
  51.  
  52. -- Data of the current pattern
  53. local function getCurrentNotes(time)
  54. local notes = patterns[currentPattern].channels[currentChannel].notes[time]
  55. if (notes == nil) then
  56. return ""
  57. else
  58. return notes
  59. end
  60. end
  61.  
  62. -- Data of the pattern for the specified channel
  63. local function getChannelNotes(channel, time)
  64. local notes = patterns[currentPattern].channels[channel].notes[time]
  65. if (notes == nil) then
  66. return ""
  67. else
  68. return notes
  69. end
  70. end
  71.  
  72. -- Get an instrument by name
  73. local function getInstrumentByName(name)
  74. for k, v in pairs(instruments) do
  75. if (v.name == name) then
  76. return v
  77. end
  78. end
  79. error("Invalid instrument name")
  80. end
  81.  
  82. -- Get an instrument ID by name
  83. local function getInstrumentIDByName(name)
  84. for i=1, instrumentCount do
  85. if (instruments[i].name == name) then
  86. return i
  87. end
  88. end
  89. error("Invalid instrument name")
  90. end
  91.  
  92. -- Note character to note number
  93. local function characterToNote(c)
  94. local delayed = true
  95. if (string.byte(c) >= 97) then
  96. delayed = false
  97. end
  98.  
  99. if (delayed) then
  100. return string.byte(c)-65, delayed
  101. else
  102. return string.byte(c)-97, delayed
  103. end
  104. end
  105.  
  106. -- Note number to note character
  107. local function noteToCharacter(n, delayed)
  108. if (delayed) then
  109. return string.char(tonumber(n)+65) --Mayuscula
  110. else
  111. return string.char(tonumber(n)+97) --minuscula
  112. end
  113. end
  114.  
  115. -- Pitch of a note number
  116. local function notePitch(n)
  117. return math.pow(2, (n-12)/12)
  118. end
  119.  
  120. -- Pitch of a note character
  121. local function charPitch(c)
  122. return notePitch(characterToNote(c))
  123. end
  124.  
  125. local function playSoundEffect(soundname, vol, pitch)
  126. sp[nextSpeaker].playSound(getInstrumentByName(soundname).file, vol, pitch)
  127. nextSpeaker = nextSpeaker+1
  128. if (nextSpeaker > speakerCount) then
  129. nextSpeaker = 0
  130. end
  131. end
  132.  
  133. -- Play a single note number
  134. local function playNote(inst, vol, note)
  135. sp[nextSpeaker].playSound(instruments[inst].file, vol, note)
  136. nextSpeaker = nextSpeaker+1
  137. if (nextSpeaker > speakerCount) then
  138. nextSpeaker = 0
  139. end
  140. end
  141.  
  142. -- Play a string of notes
  143. local function playBar(inst, vol, notes, delayed)
  144. for n=1, string.len(notes) do
  145. local note = string.sub(notes, n, n)
  146. if (delayed and string.byte(note) < 97) then -- If its delayed, play only uppercases
  147. playNote(inst, vol, charPitch(note))
  148. elseif (not delayed and string.byte(note) >= 97) then -- If not, play only lowercases
  149. playNote(inst, vol, charPitch(note))
  150. end
  151. end
  152. end
  153.  
  154. -- Play the delayed bar
  155. local function playCurrentBarDelayed()
  156. if (delayedAllChannels) then
  157. for i=1, instrumentCount do
  158. playBar(i, 1, getChannelNotes(i, delayTime), true)
  159. end
  160. else
  161. playBar(currentChannel, 1, getCurrentNotes(delayTime), true)
  162. end
  163. end
  164.  
  165. -- Play the bar at a specified time
  166. local function playSpecificBar(time, allChannels)
  167. delayTime = time
  168. if (allChannels) then
  169. for i=1, instrumentCount do
  170. playBar(i, 1, getChannelNotes(i, time), false)
  171. end
  172. else
  173. playBar(currentChannel, 1, getCurrentNotes(time), false)
  174. end
  175. delayedNoteTimer = os.startTimer(30/(songBpm*patterns[currentPattern].speed)-0.001)
  176. delayedAllChannels = allChannels
  177. end
  178.  
  179. -- Play the current channel's bar currently indicated by the cursor
  180. local function playCurrentChannelBar()
  181. playSpecificBar(cursor, false)
  182. end
  183.  
  184. -- Play the every bar currently indicated by the cursor
  185. local function playCurrentBar()
  186. playSpecificBar(cursor, true)
  187. end
  188.  
  189. local function updateProgress()
  190. term.setCursorPos(6, 13)
  191. local percent = songCursor/songBeats
  192. local characters = math.ceil(percent*40)
  193. term.setBackgroundColor(colors.orange)
  194. term.write(string.rep(" ", characters))
  195. term.setBackgroundColor(colors.brown)
  196. term.write(string.rep(" ", 40-characters))
  197. term.setBackgroundColor(colors.black)
  198. end
  199.  
  200. -- StartPlaying
  201. local function playFromCursor()
  202. if (songBeats > 0) then
  203. playing = true
  204. playingTimer = os.startTimer(60/(songBpm*patterns[currentPattern].speed))
  205. progressTimer = os.startTimer(1)
  206. updateProgress()
  207. playCurrentBar()
  208. term.setCursorPos(5, 12)
  209. term.setTextColor(colors.lime)
  210. term.write(" > Play ")
  211. end
  212. end
  213.  
  214. -- StartPlaying
  215. local function playFromStart()
  216. loadSong()
  217. cursor = 1
  218. songCursor = 1
  219. currentXOffset = 0
  220. playing = true
  221. playingTimer = os.startTimer(60/(songBpm*patterns[currentPattern].speed))
  222. progressTimer = os.startTimer(1)
  223. updateProgress()
  224. playCurrentBar()
  225. term.setCursorPos(5, 12)
  226. term.setTextColor(colors.lime)
  227. term.write("|> Play ")
  228. end
  229.  
  230. -- Pause
  231. local function stop()
  232. playing = false
  233. cursor = 1
  234. songCursor = 1
  235. term.setCursorPos(5, 12)
  236. term.setTextColor(colors.red)
  237. term.write("[] Stop ")
  238. end
  239.  
  240. -- Pause
  241. local function pause()
  242. playing = false
  243. term.setCursorPos(5, 12)
  244. term.setTextColor(colors.red)
  245. term.write("|| Pause ")
  246. end
  247.  
  248. local function newPattern()
  249. local p = {
  250. ["channels"] = {},
  251. ["length"] = defaultPatternLength,
  252. ["speed"] = 1,
  253. ["measure"] = defaultMeasure
  254. }
  255. for i=1, instrumentCount do
  256. p.channels[i] = {
  257. ["notes"] = {}
  258. }
  259. end
  260. return p
  261. end
  262.  
  263. local function newSong()
  264. song = {
  265. ["patterns"] = {}
  266. }
  267. currentPattern = 1
  268. patterns[currentPattern] = newPattern()
  269. end
  270.  
  271. -- Load song from disk
  272. function loadSong()
  273. local f = fs.open("disk/memsong.txt", "r")
  274.  
  275. local fileTitle = "unknown"
  276. local fileBpm = 240
  277. local fileSong = {}
  278.  
  279. newSong()
  280. patterns = {}
  281. songBeats = 0
  282.  
  283. local line = f.readLine()
  284. repeat
  285. if (line == "title") then
  286. fileTitle = f.readLine()
  287. elseif (line == "bpm") then
  288. fileBpm = tonumber(f.readLine())
  289. elseif (line == "structure") then
  290. local songPart = f.readLine()
  291. local i=1
  292. repeat
  293. fileSong[i] = tonumber(songPart)
  294. i = i+1
  295. songPart = f.readLine()
  296. until songPart == ""
  297. elseif (line == "pattern") then
  298. local currentPattern = tonumber(f.readLine())
  299. if (currentPattern ~= nil) then
  300. patterns[currentPattern] = newPattern()
  301. local pLine = f.readLine()
  302. repeat
  303. local broken = false
  304. if (pLine == "length") then
  305. patterns[currentPattern].length = tonumber(f.readLine())
  306. elseif (pLine == "measure") then
  307. patterns[currentPattern].measure = tonumber(f.readLine())
  308. elseif (pLine == "speed") then
  309. patterns[currentPattern].speed = tonumber(f.readLine())
  310. elseif (pLine == "notes") then
  311. local instrument = f.readLine()
  312. if (instrument ~= "") then
  313. repeat
  314. local noteString = f.readLine()
  315. local notes = {}
  316. local pointer = 1
  317. local spaces = 0
  318.  
  319. for i=1, string.len(noteString) do
  320.  
  321. local char = string.sub(noteString, i, i)
  322.  
  323. if (tonumber(char)) then -- If the character is a number, count spaces
  324. spaces = spaces*10
  325. spaces = spaces+tonumber(char)
  326. else
  327. pointer = pointer+spaces
  328. if (notes[pointer] == nil) then
  329. notes[pointer] = ""
  330. end
  331. notes[pointer] = notes[pointer]..char
  332. spaces = 0
  333. end
  334. end
  335.  
  336. patterns[currentPattern].channels[getInstrumentIDByName(instrument)].notes = notes
  337. songBeats = songBeats + patterns[currentPattern].length
  338.  
  339. instrument = f.readLine()
  340. until instrument == ""
  341. broken = true
  342. end
  343. end
  344. if (broken) then
  345. pLine = nil
  346. else
  347. pLine = f.readLine()
  348. end
  349. until pLine == "" or pLine == nil
  350. end
  351. end
  352. line = f.readLine()
  353. until line == "" or line == nil
  354. f.close()
  355.  
  356. song.patterns = fileSong
  357. songLength = #song.patterns
  358. songBpm = fileBpm
  359. currentSongPattern = 1
  360. currentPattern = song.patterns[1]
  361.  
  362. term.setCursorPos(1, 8)
  363. term.setTextColor(colors.yellow)
  364. term.write("Cancion: "..fileTitle)
  365. end
  366.  
  367. term.clear()
  368. term.setCursorPos(1,1)
  369. term.setBackgroundColor(colors.black)
  370. term.setTextColor(colors.orange)
  371. print("~ Memdia Player ~")
  372. print("")
  373. print("Enter: Cargar canción / Iniciar desde el principio / Pausa")
  374. print("Espacio: Pausa / Play")
  375.  
  376. -- Update
  377. while true do
  378. local event, a, b, c = os.pullEvent()
  379. if (event == "timer") then
  380. local completed = a
  381. if (completed == playingTimer) then
  382. if (playing) then
  383. local patternLength = patterns[currentPattern].length
  384. cursor = cursor+1
  385. songCursor = songCursor+1
  386. if (cursor > patternLength) then
  387. currentSongPattern = currentSongPattern+1
  388. if (currentSongPattern > songLength) then
  389. currentSongPattern = 1
  390. songCursor = 1
  391. updateProgress()
  392. end
  393. currentPattern = song.patterns[currentSongPattern]
  394. cursor = 1
  395. currentXOffset = 0
  396. end
  397. playCurrentBar()
  398. playingTimer = os.startTimer(60/(songBpm*patterns[currentPattern].speed))
  399. end
  400. elseif (completed == delayedNoteTimer) then
  401. playCurrentBarDelayed()
  402. elseif (completed == progressTimer) then
  403. if (playing) then
  404. updateProgress()
  405. progressTimer = os.startTimer(1)
  406. end
  407. end
  408. elseif (event == "key") then
  409. local key = a
  410. if (key == keys.space) then
  411. if (playing) then
  412. pause()
  413. else
  414. playFromCursor()
  415. end
  416.  
  417. elseif (key == keys.enter) then
  418. if (playing) then
  419. pause()
  420. else
  421. playFromStart()
  422. end
  423.  
  424. end
  425. end
  426. end
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement