Successfully reported this slideshow.
We use your LinkedIn profile and activity data to personalize ads and to show you more relevant ads. You can change your ad preferences anytime.

Ruby, Rock & Roll

2,915 views

Published on

Creating digital music using a Pure Ruby domain specific language

Published in: Technology, Education
  • Login to see the comments

Ruby, Rock & Roll

  1. 1. Ruby, Rock and RollChang Sau SheongHP Labs SingaporeMay 2012
  2. 2. About
  3. 3.  me
  4. 4. About
  5. 5.  me
  6. 6. About
  7. 7.  me
  8. 8. About
  9. 9.  me
  10. 10. About
  11. 11.  me
  12. 12. About
  13. 13.  me
  14. 14. About
  15. 15.  me
  16. 16. About
  17. 17.  me
  18. 18. Musehttp://github.com/sausheong/muse
  19. 19. A
  20. 20.  (pure)
  21. 21.  Ruby
  22. 22.  domain- specific
  23. 23.  language
  24. 24.  for
  25. 25.   synthesizing
  26. 26.  music
  27. 27.  
  28. 28. Creating
  29. 29.  Muse•Create
  30. 30.  sound•Organize
  31. 31.  sound
  32. 32.  into
  33. 33.  music
  34. 34.  notes•Write
  35. 35.  notes
  36. 36.  to
  37. 37.  file•Wrap
  38. 38.  around
  39. 39.  with
  40. 40.  a
  41. 41.  domain- specific
  42. 42.  language
  43. 43. About
  44. 44.  sound•Sound
  45. 45.  is
  46. 46.  produced
  47. 47.  by
  48. 48.  vibration
  49. 49.  of
  50. 50.  something
  51. 51.   (air,
  52. 52.  water
  53. 53.  etc)•Vibration
  54. 54.  produces
  55. 55.  waves
  56. 56.  •Properties
  57. 57.  of
  58. 58.  sound
  59. 59.  wave
  60. 60.  include
  61. 61.  amplitude
  62. 62.   (volume)
  63. 63.  and
  64. 64.  frequency
  65. 65.  (pitch)
  66. 66. Higher
  67. 67.  amplitude
  68. 68.  means
  69. 69.  louder
  70. 70.  volume amplitude frequency
  71. 71.  =
  72. 72.  number
  73. 73.  of
  74. 74.   cycles
  75. 75.  in
  76. 76.  1
  77. 77.  second cycle More
  78. 78.  cycles
  79. 79.  in
  80. 80.  1
  81. 81.  second
  82. 82.   mean
  83. 83.  higher
  84. 84.  frequency,
  85. 85.   higher
  86. 86.  pitch
  87. 87. Make
  88. 88.  a
  89. 89.  sound•Sine
  90. 90.  wave
  91. 91.  is
  92. 92.  pure
  93. 93.  sound,
  94. 94.  all
  95. 95.  other
  96. 96.  sounds
  97. 97.  made
  98. 98.   by
  99. 99.  combining
  100. 100.  various
  101. 101.  sine
  102. 102.  waves•To
  103. 103.  make
  104. 104.  a
  105. 105.  sound,
  106. 106.  generate
  107. 107.  sine
  108. 108.  waves•To
  109. 109.  make
  110. 110.  a
  111. 111.  digital
  112. 112.  sound,
  113. 113.  generate
  114. 114.  digital
  115. 115.  sine
  116. 116.   waves
  117. 117.  and
  118. 118.  put
  119. 119.  them
  120. 120.  into
  121. 121.  sound
  122. 122.  files
  123. 123. The
  124. 124.  physics
  125. 125.  of
  126. 126.  music•Music
  127. 127.  is
  128. 128.  organized
  129. 129.  sound•Music
  130. 130.  notes
  131. 131.  are
  132. 132.  sounds
  133. 133.  with
  134. 134.  specific
  135. 135.  pitches
  136. 136.   (frequencies)
  137. 137.  and
  138. 138.  durations•Each
  139. 139.  note
  140. 140.  corresponds
  141. 141.  to
  142. 142.  a
  143. 143.  particular
  144. 144.   frequency,
  145. 145.  expressed
  146. 146.  in
  147. 147.  hertz
  148. 148.  (Hz)•Most
  149. 149.  music
  150. 150.  use
  151. 151.  a
  152. 152.  scale
  153. 153.  (sequence
  154. 154.  of
  155. 155.  notes)
  156. 156.   with
  157. 157.  12
  158. 158.  notes
  159. 159.  called
  160. 160.  the
  161. 161.  chromatic
  162. 162.  scale
  163. 163. same
  164. 164.  pitch
  165. 165.  class
  166. 166.  (octave) C# D# F# G# A#C D E F G A B C 1
  167. 167.  octave
  168. 168.  =
  169. 169.  12
  170. 170.  semi-tone
  171. 171.  notes
  172. 172. The
  173. 173.  physics
  174. 174.  of
  175. 175.  music•The
  176. 176.  frequencies
  177. 177.  of
  178. 178.  the
  179. 179.  notes
  180. 180.  are
  181. 181.  related
  182. 182.  to
  183. 183.   each
  184. 184.  other
  185. 185.  in
  186. 186.  a
  187. 187.  mathematical
  188. 188.  formula•The
  189. 189.  frequencies
  190. 190.  are
  191. 191.  defined
  192. 192.  around
  193. 193.  the
  194. 194.   standard
  195. 195.  pitch
  196. 196.  A4,
  197. 197.  which
  198. 198.  is
  199. 199.  440
  200. 200.  Hz
  201. 201.  (ISO
  202. 202.   16:1975
  203. 203.  standard)•Notes
  204. 204.  of
  205. 205.  the
  206. 206.  same
  207. 207.  pitch
  208. 208.  class
  209. 209.  (octave)
  210. 210.  are
  211. 211.  in
  212. 212.   the
  213. 213.  ratio
  214. 214.  of
  215. 215.  a
  216. 216.  power
  217. 217.  of
  218. 218.  2
  219. 219.  (1/4,
  220. 220.  1/2,
  221. 221.  2,
  222. 222.  4,
  223. 223.  8
  224. 224.   etc)
  225. 225.  
  226. 226. A A7 3520HzA A6 1760HzA A5 880HzA A4 440Hz
  227. 227. 12difference
  228. 228.  between
  229. 229.  12
  230. 230.  semi-tones
  231. 231.  (1
  232. 232.  octave)
  233. 233.  is
  234. 234.  
  235. 235.  2
  236. 236.  
  237. 237.  
  238. 238.  ×
  239. 239.  f
  240. 240.  
  241. 241.  or
  242. 242.  2f
  243. 243.  
  244. 244.  
  245. 245.   12 1 difference
  246. 246.  between
  247. 247.  2
  248. 248.  semi-tones
  249. 249.  is
  250. 250.  
  251. 251.  
  252. 252.  
  253. 253.  2
  254. 254.  ×
  255. 255.  f
  256. 256.  
  257. 257.  or
  258. 258.   2
  259. 259.  
  260. 260.   12 12 ×f
  261. 261. Getting
  262. 262.  the
  263. 263.  frequency•Get
  264. 264.  the
  265. 265.  frequency
  266. 266.  of
  267. 267.  the
  268. 268.  note
  269. 269.  (f),
  270. 270.  as
  271. 271.   compared
  272. 272.  to
  273. 273.  A4
  274. 274.  (440Hz)
  275. 275.  using
  276. 276.  the
  277. 277.  formula n f = 2 × 440Hz 12•where
  278. 278.  n
  279. 279.  =
  280. 280.  distance
  281. 281.  from
  282. 282.  A4.
  283. 283.  For
  284. 284.  eg
  285. 285.  C5
  286. 286.  is
  287. 287.  3
  288. 288.   notes
  289. 289.  (semi-tones)
  290. 290.  after
  291. 291.  A4,
  292. 292.  so
  293. 293.  frequency
  294. 294.  of
  295. 295.   C5
  296. 296.  is
  297. 297.   3 f = 2 12 × 440Hz = 523.25Hz
  298. 298. Create
  299. 299.  music
  300. 300.  notes•To
  301. 301.  get
  302. 302.  a
  303. 303.  sine
  304. 304.  wave
  305. 305.  representing
  306. 306.  a
  307. 307.  note s = sin(2π f )• We
  308. 308.  multiple
  309. 309.  f
  310. 310.  with
  311. 311.  2
  312. 312.  
  313. 313.  
  314. 314.  because
  315. 315.  we
  316. 316.  need
  317. 317.  to
  318. 318.  
  319. 319.   π turn
  320. 320.  the
  321. 321.  frequency
  322. 322.  into
  323. 323.  radians
  324. 324. Get
  325. 325.  note
  326. 326.  data
  327. 327.  samples 1250 626 0 44100
  328. 328.  samples take
  329. 329.  samples
  330. 330.  at
  331. 331.  regular
  332. 332.  intervals
  333. 333.  (44,100
  334. 334.   samples
  335. 335.  over
  336. 336.  a
  337. 337.  period
  338. 338.  of
  339. 339.  1
  340. 340.  second)
  341. 341.  and
  342. 342.   calculate
  343. 343.  the
  344. 344.  wave
  345. 345.  value
  346. 346.  at
  347. 347.  that
  348. 348.  sample
  349. 349. NOTES = %w(a ais b c cis d dis e f fis g gis)FREQUENCIES = { d4:-7, dis4:-6, e4:-5, f4: -4, fis4:-3, g4:-2, gis4:-1, a4: 0, ais4: 1, b4: 2, c5: 3, cis5: 4, d5: 5}# get the frequency of the pitchdef frequency_of(step) 440.0*(2**(step.to_f/12.0))endsample_rate = 44100.0 # 44100 Hzduration = 1 # 1 secstream = [] # data stream for left and right channelsfrequency = frequency_of(FREQUENCIES[:a4])# for the duration of 1 sec, step every 1/44100 times and# write the value(0.0..duration.to_f).step(1/sample_rate) do |i| x = (10000 * Math.sin(2 * Math::PI * frequency * i)).to_i stream [x,x]end
  350. 350. [[0, 0], [626, 626], [1250, 1250], [1869, 1869], [2481, 2481], [3083, 3083], [3673, 3673], [4248, 4248], [4807, 4807], [5347, 5347], [5866, 5866], [6362,6362], [6832, 6832], [7276, 7276], [7692, 7692], [8077, 8077], [8431, 8431], [8751, 8751], [9037, 9037], [9287, 9287], [9501, 9501], [9678, 9678], [9816,9816], [9916, 9916], [9978, 9978], [9999, 9999], [9982, 9982], [9925, 9925], [9830, 9830], [9696, 9696], [9523, 9523], [9313, 9313], [9067, 9067], [8785,8785], [8469, 8469], [8119, 8119], [7737, 7737], [7325, 7325], [6884, 6884], [6416, 6416], [5923, 5923], [5407, 5407], [4869, 4869], [4313, 4313], [3739,3739], [3151, 3151], [2550, 2550], [1939, 1939], [1321, 1321], [697, 697], [71, 71], [-555, -555], [-1179, -1179], [-1799, -1799], [-2412, -2412], [-3015,-3015], [-3606, -3606], [-4184, -4184], [-4744, -4744], [-5287, -5287], [-5808, -5808], [-6307, -6307], [-6780, -6780], [-7227, -7227], [-7646, -7646], stream[-8035, -8035], [-8392, -8392], [-8716, -8716], [-9006, -9006], [-9261, -9261], [-9479, -9479], [-9660, -9660], [-9803, -9803], [-9907, -9907], [-9973,-9973], [-9999, -9999], [-9986, -9986], [-9934, -9934], [-9843, -9843], [-9713, -9713], [-9545, -9545], [-9339, -9339], [-9097, -9097], [-8819, -8819],[-8506, -8506], [-8160, -8160], [-7782, -7782], [-7373, -7373], [-6936, -6936], [-6471, -6471], [-5981, -5981], [-5467, -5467], [-4931, -4931], [-4377,-4377], [-3805, -3805], [-3218, -3218], [-2619, -2619], [-2009, -2009], [-1391, -1391], [-768, -768], [-142, -142], [484, 484], [1109, 1109], [1729, 1729],[2343, 2343], [2947, 2947], [3540, 3540], [4119, 4119], [4682, 4682], [5226, 5226], [5750, 5750], [6251, 6251], [6728, 6728], [7178, 7178], [7600, 7600],[7992, 7992], [8353, 8353], [8681, 8681], [8975, 8975], [9234, 9234], [9456, 9456], [9641, 9641], [9788, 9788], [9897, 9897], [9967, 9967], [9998, 9998],[9989, 9989], [9942, 9942], [9855, 9855], [9729, 9729], [9566, 9566], [9364, 9364], [9126, 9126], [8852, 8852], [8544, 8544], [8201, 8201], [7827, 7827],[7421, 7421], [6987, 6987], [6525, 6525], [6038, 6038], [5526, 5526], [4993, 4993], [4441, 4441], [3871, 3871], [3285, 3285], [2687, 2687], [2079, 2079],[1462, 1462], [839, 839], [213, 213], [-413, -413], [-1038, -1038], [-1659, -1659], [-2273, -2273], [-2879, -2879], [-3473, -3473], [-4054, -4054], [-4619,-4619], [-5165, -5165], [-5691, -5691], [-6195, -6195], [-6675, -6675], [-7128, -7128], [-7554, -7554], [-7949, -7949], [-8314, -8314], [-8645, -8645],[-8943, -8943], [-9206, -9206], [-9432, -9432], [-9622, -9622], [-9774, -9774], [-9887, -9887], [-9961, -9961], [-9996, -9996], [-9992, -9992], [-9949,-9949], [-9867, -9867], [-9746, -9746], [-9586, -9586], [-9389, -9389], [-9155, -9155], [-8885, -8885], [-8580, -8580], [-8242, -8242], [-7871, -7871],[-7469, -7469], [-7038, -7038], [-6579, -6579], [-6094, -6094], [-5586, -5586], [-5055, -5055], [-4504, -4504], ...]
  351. 351. [[0, 0], [626, 626], [1250, 1250], [1869, 1869], [2481, 2481], [3083, 3083], [3673, 3673], [4248, 4248], [4807, 4807], [5347, 5347], [5866, 5866], [6362,6362], [6832, 6832], [7276, 7276], [7692, 7692], [8077, 8077], [8431, 8431], [8751, 8751], [9037, 9037], [9287, 9287], [9501, 9501], [9678, 9678], [9816,9816], [9916, 9916], [9978, 9978], [9999, 9999], [9982, 9982], [9925, 9925], [9830, 9830], [9696, 9696], [9523, 9523], [9313, 9313], [9067, 9067], [8785,8785], [8469, 8469], [8119, 8119], [7737, 7737], [7325, 7325], [6884, 6884], [6416, 6416], [5923, 5923], [5407, 5407], [4869, 4869], [4313, 4313], [3739,3739], [3151, 3151], [2550, 2550], [1939, 1939], [1321, 1321], [697, 697], [71, 71], [-555, -555], [-1179, -1179], [-1799, -1799], [-2412, -2412], [-3015,-3015], [-3606, -3606], [-4184, -4184], [-4744, -4744], [-5287, -5287], [-5808, -5808], [-6307, -6307], [-6780, -6780], [-7227, -7227], [-7646, -7646], stream[-8035, -8035], [-8392, -8392], [-8716, -8716], [-9006, -9006], [-9261, -9261], [-9479, -9479], [-9660, -9660], [-9803, -9803], [-9907, -9907], [-9973,-9973], [-9999, -9999], [-9986, -9986], [-9934, -9934], [-9843, -9843], [-9713, -9713], [-9545, -9545], [-9339, -9339], [-9097, -9097], [-8819, -8819],[-8506, -8506], [-8160, -8160], [-7782, -7782], [-7373, -7373], [-6936, -6936], [-6471, -6471], [-5981, -5981], [-5467, -5467], [-4931, -4931], [-4377,-4377], [-3805, -3805], [-3218, -3218], [-2619, -2619], [-2009, -2009], [-1391, -1391], [-768, -768], [-142, -142], [484, 484], [1109, 1109], [1729, 1729],[2343, 2343], [2947, 2947], [3540, 3540], [4119, 4119], [4682, 4682], [5226, 5226], [5750, 5750], [6251, 6251], [6728, 6728], [7178, 7178], [7600, 7600],[7992, 7992], [8353, 8353], [8681, 8681], [8975, 8975], [9234, 9234], [9456, 9456], [9641, 9641], [9788, 9788], [9897, 9897], [9967, 9967], [9998, 9998],[9989, 9989], [9942, 9942], [9855, 9855], [9729, 9729], [9566, 9566], [9364, 9364], [9126, 9126], [8852, 8852], [8544, 8544], [8201, 8201], [7827, 7827],[7421, 7421], [6987, 6987], [6525, 6525], [6038, 6038], [5526, 5526], [4993, 4993], [4441, 4441], [3871, 3871], [3285, 3285], [2687, 2687], [2079, 2079],[1462, 1462], [839, 839], [213, 213], [-413, -413], [-1038, -1038], [-1659, -1659], [-2273, -2273], [-2879, -2879], [-3473, -3473], [-4054, -4054], [-4619,-4619], [-5165, -5165], [-5691, -5691], [-6195, -6195], [-6675, -6675], [-7128, -7128], [-7554, -7554], [-7949, -7949], [-8314, -8314], [-8645, -8645],[-8943, -8943], [-9206, -9206], [-9432, -9432], [-9622, -9622], [-9774, -9774], [-9887, -9887], [-9961, -9961], [-9996, -9996], [-9992, -9992], [-9949,-9949], [-9867, -9867], [-9746, -9746], [-9586, -9586], [-9389, -9389], [-9155, -9155], [-8885, -8885], [-8580, -8580], [-8242, -8242], [-7871, -7871],[-7469, -7469], [-7038, -7038], [-6579, -6579], [-6094, -6094], [-5586, -5586], [-5055, -5055], [-4504, -4504], ...]
  352. 352. Harmonics•Sine
  353. 353.  wave
  354. 354.  is
  355. 355.  the
  356. 356.  most
  357. 357.  basic
  358. 358.  waveform
  359. 359.  and
  360. 360.   produces
  361. 361.  the
  362. 362.  fundamental
  363. 363.  frequency,
  364. 364.  a
  365. 365.  pure
  366. 366.   sound•Any
  367. 367.  other
  368. 368.  sounds
  369. 369.  can
  370. 370.  be
  371. 371.  created
  372. 372.  by
  373. 373.  adding
  374. 374.   other
  375. 375.  waves
  376. 376.  at
  377. 377.  different
  378. 378.  frequencies
  379. 379.  and
  380. 380.   amplitudes
  381. 381.  (called
  382. 382.  harmonics)•Adding
  383. 383.  sine
  384. 384.  waves
  385. 385.  at
  386. 386.  different
  387. 387.  multiples
  388. 388.  of
  389. 389.   the
  390. 390.  same
  391. 391.  frequency
  392. 392.  changes
  393. 393.  how
  394. 394.  the
  395. 395.  same
  396. 396.  note
  397. 397.   sounds
  398. 398. y=sin(x)y
  399. 399.  =
  400. 400.  sin(2x) y
  401. 401.  =
  402. 402.  sin(x)
  403. 403.  +
  404. 404.  sin(2x)
  405. 405. def harmonics(input) Math.sin(2 * Math::PI * input) + Math.sin(2 * Math::PI * input * 2)end# for the duration of 1 sec, step every 1/44100 times and# write the value(0.0..duration.to_f).step(1/sample_rate) do |i| x = (10000 * harmonics(frequency * i)).to_i stream [x,x]end
  406. 406. def harmonics(input) Math.sin(2 * Math::PI * input) + Math.sin(2 * Math::PI * input * 2)end# for the duration of 1 sec, step every 1/44100 times and# write the value(0.0..duration.to_f).step(1/sample_rate) do |i| x = (10000 * harmonics(frequency * i)).to_i stream [x,x]end
  407. 407. Envelopes•Changing
  408. 408.  the
  409. 409.  volume
  410. 410.  of
  411. 411.  the
  412. 412.  note
  413. 413.  over
  414. 414.  the
  415. 415.   duration
  416. 416.  also
  417. 417.  changes
  418. 418.  how
  419. 419.  the
  420. 420.  note
  421. 421.  sounds def envelope(input, duration) Math.cos((Math::PI*input)/(2*duration.to_f)) end # for the duration of 1 sec, step every 1/44100 times and # write the value (0.0..duration.to_f).step(1/sample_rate) do |i| x = (10000 * Math.sin(2 * Math::PI * frequency * i) * envelope(i, duration)).to_i stream [x,x] end
  422. 422. input
  423. 423.  x
  424. 424.  sin(duration)input
  425. 425.  x
  426. 426.  cos(duration)
  427. 427. input
  428. 428.  x
  429. 429.  sin(duration)input
  430. 430.  x
  431. 431.  cos(duration)
  432. 432. input
  433. 433.  x
  434. 434.  sin(duration)input
  435. 435.  x
  436. 436.  cos(duration)
  437. 437. Digital
  438. 438.  sound•Digital
  439. 439.  sound
  440. 440.  stored
  441. 441.  in
  442. 442.  compressed
  443. 443.  or
  444. 444.   uncompressed
  445. 445.  formats•Main
  446. 446.  uncompressed
  447. 447.  format
  448. 448.  is
  449. 449.  PCM
  450. 450.  (Pulse
  451. 451.  Code
  452. 452.   Modulation),
  453. 453.  stored
  454. 454.  as
  455. 455.  WAV
  456. 456.  (Windows)
  457. 457.  or
  458. 458.   AIFF
  459. 459.  (Mac)
  460. 460.  files•Standard
  461. 461.  form
  462. 462.  for
  463. 463.  all
  464. 464.  digital
  465. 465.  audio,
  466. 466.  digital
  467. 467.   representation
  468. 468.  of
  469. 469.  an
  470. 470.  analog
  471. 471.  signal
  472. 472. The
  473. 473.  WAV
  474. 474.  format•Audio
  475. 475.  file
  476. 476.  format
  477. 477.  for
  478. 478.  Windows,
  479. 479.  derived
  480. 480.  from
  481. 481.   RIFF
  482. 482.  (Resource
  483. 483.  Interchange
  484. 484.  File
  485. 485.  Format)•Bitstream
  486. 486.  format
  487. 487.  store
  488. 488.  data
  489. 489.  in
  490. 490.  chunks•Linear
  491. 491.  PCM
  492. 492.  encoded,
  493. 493.  2
  494. 494.  channels
  495. 495.  of
  496. 496.  44,100
  497. 497.   samples
  498. 498.  per
  499. 499.  second,
  500. 500.  16
  501. 501.  bits
  502. 502.  per
  503. 503.  sample
  504. 504. Create
  505. 505.  WAV
  506. 506.  files•Write
  507. 507.  manually
  508. 508.  using
  509. 509.  Array#pack
  510. 510.  (read
  511. 511.   manually
  512. 512.  using
  513. 513.  String#unpack)•Use
  514. 514.  the
  515. 515.  BinData
  516. 516.  library
  517. 517.  (http:// bindata.rubyforge.org)
  518. 518.  to
  519. 519.  represent
  520. 520.  WAV
  521. 521.   format
  522. 522.  and
  523. 523.  stuff
  524. 524.  data
  525. 525.  in•Data
  526. 526.  is
  527. 527.  just
  528. 528.  integers
  529. 529.  representing
  530. 530.  the
  531. 531.  sample
  532. 532. require bindataclass RiffChunk BinData::Record int32be :chunk_id int32le :chunk_size int32be :formatendclass FormatChunk BinData::Record int32be :chunk_id int32le :chunk_size int16le :audio_format int16le :num_channels int32le :sample_rate int32le :byte_rate int16le :block_align int16le :bits_per_sampleendclass DataChunk BinData::Record int32be :chunk_id int32le :chunk_size array :stream do int16le :left int16le :right endendclass WavFormat BinData::Record riff_chunk :riff_chunk format_chunk :format_chunk data_chunk :data_chunkend
  533. 533. class Wav SAMPLE_RATE = 44100 attr :wav, :file, :sample_rate, :format_chunk, :riff_chunk, :data_chunk def initialize(filename) @sample_rate = SAMPLE_RATE @file = File.open(filename, wb) @riff_chunk = RiffChunk.new @riff_chunk.chunk_id = RIFF.unpack(N).first @riff_chunk.format = WAVE.unpack(N).first @format_chunk = FormatChunk.new @format_chunk.chunk_id = fmt .unpack(N).first @format_chunk.chunk_size = 16 @format_chunk.audio_format = 1 @format_chunk.num_channels = 2 @format_chunk.bits_per_sample = 16 @format_chunk.sample_rate = @sample_rate @format_chunk.byte_rate = @format_chunk.sample_rate * @format_chunk.num_channels * @format_chunk.bits_per_sample/2 @format_chunk.block_align = @format_chunk.num_channels * @format_chunk.bits_per_sample/2 @data_chunk = DataChunk.new @data_chunk.chunk_id = data.unpack(N).first end
  534. 534. def write(stream_data) stream_data.each_with_index do |s,i| @data_chunk.stream[i].left = s[0] @data_chunk.stream[i].right = s[1] end @data_chunk.chunk_size = stream_data.length * @format_chunk.num_channels * @format_chunk.bits_per_sample/8 @riff_chunk.chunk_size = 36 + @data_chunk.chunk_size @wav = WavFormat.new @wav.riff_chunk = @riff_chunk @wav.format_chunk = @format_chunk @wav.data_chunk = @data_chunk @wav.write(@file) end def close @file.close endendwav_file = Wav.new(sine.wav)wav_file.write(stream)wav_file.close
  535. 535. Putting
  536. 536.  it
  537. 537.  all
  538. 538.   together
  539. 539. NOTES = %w(a ais b c cis d dis e f fis g gis)FREQUENCIES = { d4:-7, dis4:-6, e4:-5, f4:-4, fis4:-3, g4:-2, gis4:-1, a4: 0, ais4: 1, b4: 2, c5: 3, cis5: 4, d5: 5}# get the frequency of the pitchdef frequency_of(step) 440.0*(2**(step.to_f/12.0))endsample_rate = 44100.0 # 44100 Hzduration = 1 # 1 secstream = [] # data stream for left and right channelsfrequency = frequency_of(FREQUENCIES[:a4])# for the duration of 1 sec, step every 1/44100 times and# write the value(0.0..duration.to_f).step(1/sample_rate) do |i| x = (10000 * Math.sin(2 * Math::PI * frequency * i)).to_i stream [x,x]endwav_file = Wav.new(sine.wav)wav_file.write(stream)wav_file.close
  540. 540. Domain
  541. 541.  specific
  542. 542.  language•Designed
  543. 543.  for
  544. 544.  a
  545. 545.  specific
  546. 546.  domain•Captures
  547. 547.  concepts
  548. 548.  of
  549. 549.  the
  550. 550.  domain
  551. 551.  including
  552. 552.   jargon•Is
  553. 553.  still
  554. 554.  Ruby!
  555. 555. Techniques
  556. 556.  used
  557. 557.  in
  558. 558.  Muse•DSL
  559. 559.  are
  560. 560.  methods
  561. 561.  in
  562. 562.  Song
  563. 563.  and
  564. 564.  Bar•Use
  565. 565.  instance_eval
  566. 566.  to
  567. 567.  evaluate
  568. 568.  music
  569. 569.  score•Use
  570. 570.  method_missing
  571. 571.  to
  572. 572.  catch
  573. 573.  names
  574. 574.  of
  575. 575.  notes
  576. 576.   and
  577. 577.  chords
  578. 578. class Song DSL
  579. 579.  are
  580. 580.  methods def self.record(name, options ={}, block) ... def bar(id, options={}) ... @bars[id] Bar.new(id, options) @bars[id].last end end class Bar def notes(block) ... end end endrequire museinclude MuseSong.record hotel_california, harmonic: guitar, bpm: 100 do bar(1).notes { d4 b:2; e4; fis4;} ...end
  581. 581. instance_evalclass Bar ... def notes(block) instance_eval block endendrequire museinclude MuseSong.record hotel_california, harmonic: guitar, bpm: 100 do bar(1).notes { d4 b:2; e4; fis4;} ...end
  582. 582. method_missingclass Bar ... def method_missing(name, *args, block) name = name.to_s if name.start_with? *NOTES ... end endendrequire museinclude MuseSong.record hotel_california, harmonic: guitar, bpm: 100 do ... bar(3).notes { a3_d4_fis4; fis4; fis4 b:0.5;} ...end
  583. 583. Turk!h March
  584. 584. Wait,
  585. 585.  there’s
  586. 586.   more
  587. 587.  ...
  588. 588. Ottothe Algorithmic Composer
  589. 589. Algorithmic composition is thetechnique of using algorithms to create music - Wikipedia
  590. 590. Grab tweet from Twitter, create music from it
  591. 591. Scan a pictureGrab tweet from Twitter, create music from it
  592. 592. Get today’s weather report Scan a picture Grab tweet from Twitter, create music from it
  593. 593. The algorithm
  594. 594. Melody + Chords = Music
  595. 595. Grab tweet from Twittertext = Twitter.search(#reddot).last.text
  596. 596. Split tweet into wordswords = text.split
  597. 597. Convert each word into anumber using the touch tone keypad algorithm
  598. 598. KEYPAD = {a:2,b:2,c:2, d:3,e:3,f:3, g:4,h:4,i:4, j:5,k:5,l:5, m:6,n:6,o:6, p:7,q:7,r:7,s:7, t:8,u:8,v:8, w:9,x:9,y:9,z:9}def word_to_num(a_word) a_word.downcase.chars.inject() { |memo,obj| memo + KEYPAD[obj.to_sym].to_s }end
  599. 599. Find the 7 most frequently found notesmusic = []words.each do |w| music NOTES[note(w)]endsorted = music.counts.sort_by {|obj| obj[1]}.reversemost_frequent_7_notes = sorted.map {|obj| obj[0]}.first(7)
  600. 600. Determine the musical scale from the 7 notesMAJOR = { 0 = %w(c d e f g a b c d), 1 = %w(g a b c d e fis g a), 2 = %w(d e fis g a b cis d e), 3 = %w(a b cis d e fis gis a b), 4 = %w(e fis gis a b cis dis e fis), 5 = %w(b cis dis e fis gis ais b cis), 6 = %w(fis gis ais b cis dis f fis gis) }num_of_sharps = most_frequent_7_notes.inject(0) { |memo, obj| obj.end_with?(is) ? memo + 1 : memo }scale = MAJOR[num_of_sharps]
  601. 601. Get the chord progression for the scale (using I-IV-V)scale_chords = {}scale_chords[0] = [#{scale[0]}, #{scale[2]}, #{scale[4]}]scale_chords[1] = [#{scale[3]}, #{scale[5]}, #{scale[7]}]scale_chords[2] = [#{scale[4]}, #{scale[6]}, #{scale[8]}]
  602. 602. ✓Melody + Chords = Music
  603. 603. Start with the first note of the scale
  604. 604. Calculate the ‘distance’ between the current note and the nextdef distance(a_word) word_to_num(a_word).to_i % 5end
  605. 605. Determine if the next note goes ‘up’ or ‘down’ the scaledef direction(a_word) (word_to_num(a_word).to_i % 2) == 0 ? 1 : -1end
  606. 606. Get number of syllables for each word, each syllable is 1 beatdef syllables(a_word) word = a_word.downcase return 1 if word.length = 3 word.sub!(/(?:[^laeiouy]es|ed|[^laeiouy]e)$/, ) word.sub!(/^y/, ) word.scan(/[aeiouy]{1,2}/).sizeend
  607. 607. Move from current note to next noteif direction(word) 0 bar_notes scale.next(distance(word))else bar_notes scale.previous(distance(word))end
  608. 608. ✓ ✓Melody + Chords = Music
  609. 609. Break down into 4 words perbar, use Muse to write to WAV file
  610. 610. quadruplets.reverse.each_with_index do |quad, index| beats = 0.0 bar(index).notes { beats, bar_notes = [], [] quad.each do |word| beats syllables(word).to_f/2 if direction(word) 0 bar_notes scale.next(distance(word)) else bar_notes scale.previous(distance(word)) end end total_beats = beats.inject(:+) bar_notes.each_with_index do |n,i| note = n.chop octave = n[n.size-1] b = (beats[i]*4.0)/total_beats add_to_stream note_data(note, octave, b:b) end } bar(index, v:1.5).notes { ch = scale_chords[index % 3] chord = [ch[1], ch[2], ch[0]] add_to_stream note_data(ch[0].chop, 3, b:1) add_to_stream chord(chord, b:1) add_to_stream chord(chord, b:1) add_to_stream chord(chord, b:1) }
  611. 611. Demo
  612. 612. @sausheong+Sau Sheong Changsausheong@gmail.comsausheong@hp.comhttp://blog.saush.com

×