Ruby như một công cụ sáng tác: Sonic Pi
(bhmt.dev)- Sonic Pi được giới thiệu như một môi trường giúp tạo nhạc mà không cần nhạc cụ hay thiết bị; với DSL dựa trên Ruby, bạn có thể viết trực tiếp nốt, hợp âm, thang âm và thời điểm phát
- Khi tận dụng hàm, mảng, câu điều kiện, vòng lặp và scope của Ruby, có thể kết hợp
play,sleep,play_pattern_timed,chord,scaleđể cấu trúc các mẫu lặp và arpeggio một cách ngắn gọn - Kết hợp
in_thread,ring,flatten, toán tử splat vàwith_fxcho phép chạy đồng thời nhiều “nhạc cụ” và layer các nốt chồng lên nhau cùng những nhịp điệu khác nhau - Việc điều chỉnh
attack,decay,sustain,releasecủa envelope ADSR tập trung vào thời lượng duy trì và độ tách bạch hơn là tái hiện hợp xướng thật live_loopcó thể cập nhật và lặp lại mã đang phát, biến Sonic Pi thành công cụ cho biểu diễn trực tiếp, đồng thời khiến mã được nhìn nhận như một văn bản để đọc và một hành vi sáng tạo
Điều khiển Sonic Pi bằng mã
- Khác với các ứng dụng âm thanh thông thường, Sonic Pi là synthesizer phần mềm được điều khiển hoàn toàn bằng mã
- Ngôn ngữ điều khiển riêng của nó là một ngôn ngữ chuyên biệt theo miền (DSL) mở rộng từ Ruby, ánh xạ các khái niệm âm nhạc và âm thanh lên cú pháp Ruby
- Các thành phần cơ bản gồm các giá trị Ruby và hàm Sonic Pi
- Tên nốt như
:c4được dùng như symbol tương ứng với mã MIDI đó - Có thể tạo hợp âm bằng cách truyền nốt gốc và cấu trúc hợp âm làm đối số, như
chord(:d3, :maj7) playphát một nốt, còn kết hợp vớisleepcủa Ruby để điều khiển khoảng thời gianplay_pattern_timednhận danh sách nốt và khoảng thời gian, giúp rút gọn mã phát lặp
- Tên nốt như
- Mục tiêu của ví dụ là tạo phần đệm demo bằng mã chỉ với các chức năng cơ bản của Sonic Pi, không dùng MIDI hay sample bên ngoài
- Sau khi cài ứng dụng Sonic Pi, bạn có thể dán mã ví dụ vào để làm theo; tài liệu ngôn ngữ và tutorial cũng được cung cấp sẵn
Tạo mẫu lặp bằng cú pháp Ruby
- Ví dụ cơ bản đổi BPM bằng
use_bpm 70và dùng synthesizer pulse bằnguse_synth :pulsethay cho sóng sin mặc định - Lặp lại
play :c2,sleep 0.25sẽ phát các nốt theo thứ tự, và có thể viết cùng cấu trúc đó ngắn hơn bằngplay_pattern_timed [ :c3, :d3, :e3, :g3 ], 0.25 - Vì ngôn ngữ điều khiển nằm trên Ruby, có thể trừu tượng hóa pattern bằng hàm và vòng lặp
- Hàm
arpeggiatenhận nốt gốc và tùy chọn có phải giọng thứ hay không để tạo pattern đi lên và đi xuống - Vòng lặp
4.timeschạy cùng một pattern qua nhiều quãng tám - Câu điều kiện thay đổi nốt thứ ba khi là giọng thứ, còn
mapcủa mảng tạo danh sách nốt bằng cách cộng quãng vào nốt gốc
- Hàm
- Có thể đặt trước tùy chọn mặc định của synthesizer như
use_synth_defaults amp: 0.1, hoặc truyền tùy chọn trực tiếp choplayhayplay_pattern_timed - Trong Ruby, dấu ngoặc khi gọi hàm là tùy chọn, nhưng với trường hợp như
play chord(:a3, maj7), có thể cần làm rõ cách phân tách
Chạy song song và layering
- Khối
in_thread dođược dùng trong Sonic Pi để chạy mã song song - Đặt các khối
in_threadkhác nhau cho phép chạy đồng thời hai “nhạc cụ” riêng biệt- Một thread có thể đảm nhận pattern arpeggio
- Thread khác có thể dùng
use_synth :sawcùng mảng giai điệu và mảng tiết tấu để phát một tuyến giai điệu riêng
play_pattern_timedcó thể nhận không chỉ danh sách nốt mà cả danh sách khoảng thời gian[1] * 2mở rộng độ dài mảng bằng cách lặp nội dung, như[1, 1]- Vì
play_pattern_timedkhông nhận nguyên trạng mảng lồng nhau, cần dùngflattenđể dàn thành mảng một lớp
- Khi tạo các nốt chồng lên nhau như hợp xướng, có thể nhóm nhiều nốt lại với nhau như
ring(:c5, :e5) flattencó thể gộp cả danh sách bên trongring, nên trong trường hợp này dùng toán tử splat*để bung nội dung danh sách vào mảng cha
Scope, hiệu ứng và cấu trúc phần hợp xướng
- Khi dùng
in_threadlồng nhau, có thể chia sẻ các đoạn tiết tấu ở scope bên ngoài, đồng thời tái sử dụng cùng tên biến trong từng thread bên trong - Nếu tách các bè như soprano và alto thành các thread riêng, mỗi khối có scope riêng nên không truy cập trực tiếp vào biến của nhau
with_fx :reverb, mix: 0.2tạo một khối hiệu ứng; luồng tín hiệu bắt đầu từ layer trong cùng rồi di chuyển ra chuỗi hiệu ứng bên ngoàimixbiểu thị mức pha trộn giữa tín hiệu wet và dry- Tín hiệu wet là tín hiệu đã được áp dụng hiệu ứng
- Tín hiệu dry là tín hiệu không có hiệu ứng
- Bọc toàn bộ nhóm bằng một hiệu ứng có thể dùng tương tự bus trong DAW, nhưng routing sâu hơn mang tính thủ công và do scope nên nhìn chung phải cấu trúc từ trên xuống dưới
- Với Sonic Pi, cách tự nhiên hơn là xem nó như một nhạc cụ để chơi hơn là một công cụ production tinh vi
Khớp độ dài nốt bằng envelope ADSR
play_pattern_timedthêm giá trịsustain, nên có thể trực tiếp khớp thời lượng duy trì của hợp âm dài và ngắnattack,decay,sustain,releaselà envelope ADSR, mô tả âm lượng thay đổi theo thời gian như thế nàoattacklà thời gian từ 0 đến đỉnh đầu tiên, tương ứng với cú đánh ban đầu như khi gảy dây guitar hoặc búa đàn piano chạm dâydecaylà thời gian giảm xuống từ đỉnh đầu tiên, tương ứng với đoạn âm thanh giảm dần ngay cả khi vẫn giữ phím piano hoặc dây guitarsustainlà thời gian duy trì âm thanh ở mức âm lượng ổn định, như âm thanh được giữ của dây kéo bằng vĩ hoặc giọng hát kéo dàireleaselà thời gian từ sau khi nhả âm cho đến khi âm thực sự im hẳn
- Không phải âm thanh nào cũng có đầy đủ các yếu tố ADSR
- Tone synthesizer là âm được tạo ra, nên không nhất thiết có phần build-up ban đầu hay dư âm
- Nhạc cụ tự nhiên có tỷ lệ các yếu tố khác nhau tùy cách chơi
- Mô phỏng hợp xướng trong ví dụ tập trung vào việc giữ nốt đúng trong khoảng thời gian chính xác và tạo một chút tách bạch giữa các hợp âm, hơn là cảm giác chân thực
- Hàm
choral_rings notes, susnhận danh sách nốt và thời lượng duy trì, phát chúng cùng nhau bằngring(*notes), tínhsustainvàrelease, rồi chờ đến sự kiện tiếp theo bằngsleep sus
Live coding bằng live_loop
- Dùng
live_loopcho phép chạy lặp mã vô thời hạn - Sonic Pi là công cụ được thiết kế với nhiều cân nhắc cho biểu diễn trực tiếp, và mã trong
live_loopsẽ chạy cho đến khi chương trình dừng - Có thể thay đổi nội dung vòng lặp ngay trong khi đang phát; nếu chạy lại lệnh bắt đầu, vòng lặp đã cập nhật sẽ được áp dụng từ lần lặp tiếp theo
- Các vòng lặp
in_threadbên ngoài hiện có có thể được đổi thành dạnglive_loop :some_unique_name - Chuỗi hiệu ứng được tạo lại mỗi lần vòng lặp chạy, nên càng xếp nhiều hiệu ứng thì đặt chúng bên ngoài
live_loopsẽ rẻ hơn về tài nguyên - Ví dụ cuối gồm
live_loop :harpvàlive_loop :choir- Vòng lặp
:harpdùng synthesizer:squarevà pattern arpeggio có độ dài 0.25 - Vòng lặp
:choirdùng synthesizer:saw,sleep 64,with_fx :reverb, mix: 0.75và các lệnh gọi hàmchoral_ringsđể phát hợp âm hợp xướng
- Vòng lặp
Xem lập trình như một hành vi sáng tạo
- Công việc kỹ thuật thường được thảo luận từ góc nhìn khoa học máy tính, nhưng lập trình cũng có thể là nghệ thuật
- Nó không chỉ mang tính nghệ thuật khi cố ý tạo ra kết quả sáng tạo, như sinh âm thanh hay bố cục CSS
- Mã không chỉ là lệnh tối ưu cho máy, mà còn là văn bản có tổ chức để người khác và chính bạn trong tương lai đọc
- Mã tốt là mã được viết để người khác, hoặc chính bạn sau 6 tháng, có thể hiểu ngay
- Đôi khi tính nghệ thuật của mã tự nó trở thành mục đích, và ví dụ Sonic Pi cho thấy điểm đó thông qua việc sản xuất âm nhạc
1 bình luận
Ý kiến trên Hacker News
Nếu quan tâm đến live coding thì Glicol(https://glicol.org) cũng đáng thử
Cũng có TidalCycles, và khả năng tạo DSL của Haskell và Ruby thật sự rất đáng khen
Glicol tập trung vào cú pháp lấy cảm hứng từ synthesizer, tốc độ sáng tác và sự tiện lợi trong thiết kế âm thanh. Ý tưởng là đưa các thói quen lập trình sẵn có vào, nhưng thiết kế một DSL không bị mắc kẹt trong một ngôn ngữ cụ thể
https://github.com/tidalcycles/strudel
Vài năm trước tôi thấy trên YouTube một video ai đó tái hiện THX Deep Note bằng Sonic Pi
Lúc đầu họ không giải thích sẽ làm gì, chỉ tạo một “nốt” âm thanh đơn lẻ và gọi nó là con ong. Họ chỉnh dần âm thanh con ong đó và cho nghe, rồi cuối cùng diễn tiến kiểu “hãy tạo vài trăm con ong này và xem trong tổ ong sẽ nghe như thế nào”, và ngay khoảnh khắc đó Deep Note xuất hiện
Video đó thật sự rất hay nhưng từ đó tôi không tìm lại được nữa. Nếu ai biết liên kết thì mong chia sẻ
Tôi xem đây là một trong những trường hợp Ruby tỏa sáng. Nhờ metaprogramming, có thể làm cú pháp trông gần như tiếng Anh
Vài năm trước tôi từng xem Sam Aaron, tức người tạo ra Sonic Pi, biểu diễn trực tiếp bằng Sonic Pi
Mỗi khi code thay đổi theo thời gian thực, âm nhạc cũng liên tục tiến hóa, và thật sự nghe rất hay
Nếu muốn biết ví dụ nghệ sĩ dùng Sonic Pi, trước đây tôi biết đến DJ_Dave, và tôi nghĩ đó là một ví dụ hay về một nhạc sĩ tài năng, thành thạo dùng công cụ này tốt
Trước đây cô ấy cũng từng làm AMA trên Reddit, và có vẻ cũng có tác phẩm trên GitHub
[1] https://www.youtube.com/watch?v=JiQHclg_648
[2] https://www.reddit.com/r/audius/comments/19dxmy6/hey_audius_...
[3] https://github.com/algorave-dave
Với tư cách lập trình viên Ruby thì trông thật sự rất ngầu. Dùng cho âm nhạc tạo sinh bằng thuật toán có vẻ sẽ thú vị, và tôi từng muốn biến các sự kiện ồn ào trong một kho git thành một dạng nhạc thuật toán nào đó; cái này có vẻ rất hợp
Nhưng từ góc nhìn của một nhạc sĩ có nhiều nhạc cụ phím, nếu muốn sáng tác một bài thì chỉ cần chơi bằng MIDI keyboard hoặc thu âm nhạc cụ acoustic rồi loop lại, nên tôi không rõ tại sao lại phải viết chuỗi nhạc bằng Ruby. Tôi hiểu là có thể nhập thứ mình muốn bằng Ruby DSL, nhưng khó nói trải nghiệm người dùng tốt hơn so với bàn phím piano
Nói cách khác, tôi không nghĩ mình sẽ dùng nó để thay Logic. Tất nhiên đây là sở thích cá nhân
Tham khảo: http://listen.hatnote.com/
Thực tế có lúc ta nghĩ kiểu “giờ là arpeggio Đô thứ, giờ là arpeggio Fa trưởng”, và điểm hay là có thể sáng tác những ý đồ đó rất rõ ràng bằng hàm
Điểm cốt lõi có vẻ là tạo bằng thuật toán thay vì chơi từng nốt một
Dù vậy, việc tận dụng một công cụ mà bình thường có lẽ không dùng tới theo cách thú vị nhờ những ràng buộc khác thường khá phù hợp với mối quan tâm của Hacker News
Tôi có một bàn phím ưng ý và về lý thuyết cũng có thể dùng cho việc này, nhưng do vài hoàn cảnh cá nhân phức tạp mà toàn bộ nhạc cụ của tôi đã phải nằm trong kho một thời gian
Vài ngày trước tôi vừa nghĩ đến Sonic Pi và xem vài video trực tuyến
Tôi chỉ từng thử nghịch nó đôi chút vài năm trước, khi đó thử gõ vài bài cổ điển như Old MacDonald và Hot Cross Buns
Nếu muốn xem một cách tiếp cận khác với lập trình âm nhạc, tuy không phải live, scamp[0] cho Python cũng đáng xem
Người tạo ra nó đã đăng nhiều video trên YouTube về các thứ làm bằng công cụ này, ví dụ có video Fourier Elise[1]
[0] http://scamp.marcevanstein.com/
[1] https://www.youtube.com/watch?v=zq32bIud3OM
Có vẻ HTML comment không hoạt động. Có lẽ trình soạn thảo đã đổi hai dấu gạch nối
--thành một dấu em dash—Tôi cũng đề xuất live coder Sonic Pi yêu thích nhất của mình, alsoknownasrox
https://www.youtube.com/watch?v=wXIvXrBQFkE