Ruby, Rock & Roll

2,513 views
2,324 views

Published on

Creating digital music using a Pure Ruby domain specific language

Published in: Technology, Education
0 Comments
3 Likes
Statistics
Notes
  • Be the first to comment

No Downloads
Views
Total views
2,513
On SlideShare
0
From Embeds
0
Number of Embeds
30
Actions
Shares
0
Downloads
0
Comments
0
Likes
3
Embeds 0
No embeds

No notes for slide
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • \n
  • 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

    ×