Scissor を使って音声ファイルを切り貼りする

Web Music Developers JP Advent Calendar 2012

Scissor という自作のライブラリについて、4年前にリリースしてから今までまとまった紹介をしていなかった気がするので、かなりマニアックではあるが、便利な人には便利かも、なのでご紹介。

tape scissors

Scissor

インストール

$ gem install scissor

Scissor は、FFmpeg などの外部プログラムのラッパとして動作するため、外部プログラムのインストールが必要

FFmpeg

$ brew install ffmpeg

Ecasound

$ brew install ecasound

Rubber Band

$ brew install https://raw.github.com/gist/1121425/f9bb1461e45fbe3fbc0325a94e094649ac36fa43/rubberband.rb

機能

インスタンス

# ファイルから
tape = Scissor('/path/to/file.mp3')

# URL から
tape = Scissor('http://example.com/file.mp3')

# 30 秒の無音
tape = Scissor.silence(30)

カット

# 最初の一分をカット
cut = tape[0, 60]

等分

# 100 等分
tapes = tape / 100

tapes.class # => Array

結合

# 最初の15 秒と最後の15 秒をつなげる
concat = tape[0, 15] + tape[tape.duration - 15, 15]

繰り返し

# 最初の1 秒を10 回繰り返す
looped = tape[0, 1] * 10

ピッチ変更

# 最初の10 秒を半分のピッチに変更する
slow = tape[0, 10].pitch(50)

タイムストレッチ

# 最初の10 秒をピッチを変えずに二倍の長さにする
stretched = tape[0, 10].stretch(200)

パン

# 左にパンする
left_only = tape.pan(0)

# 右にパンする
right_only = tape.pan(100)

逆回し

reversed = tape.reverse

保存

保存されるファイルのフォーマットは拡張子から判定される

# 上書きしない(ファイルがすでにあった場合はエラー)
(Scissor.join(tapes) + concat + cut + loop + slow + screwed) >  '/path/to/new_file.m4a'

# 上書きする
(Scissor.join(tapes) + concat + cut + loop + slow + screwed) >> '/path/to/new_file.wav'

ミックスして保存

Scissor.mix([left_only, right_only], '/path/to/new_file.mp3')

例: ライヒ化

# -*- coding: utf-8 -*-
require 'scissor'

# ループ回数
num   = 400

# 元の音声ファイルをコマンド引数から指定
src   = Scissor(ARGV[0])

# (ループ回数 - 1)回のループがループ回数分のループと等しい長さになるようにピッチを調整する
pitch = ((src.duration * (num - 1)) / (src.duration * num)) * 100

Scissor.mix(
  [
    # 左: 元のピッチ
    (src * num).pan(0),

    # 右: 調整後のピッチ
    (src * (num - 1)).pitch(pitch).pan(100)
  ],
  'reichify.wav', :overwrite => true
);

楽曲構造を元に切り貼りする

Scissor の拡張ライブラリ、scissor-echonestを使うと、楽曲構造(ビート、小節など)を自動認識して切り貼りできる

Echo Nest APIAPI keyが必要

インストール

$ gem install scissor-echonest

例: ワルツ化

参考: Waltzify

# -*- coding: utf-8 -*-
require 'scissor/echonest'

# Echo Nest API key の指定
# ~/.echonest/api_key にAPI key が書かれたファイルを配置しておいてもよい
Scissor.echonest_api_key = 'YOUR_API_KEY'

# 元の音声ファイルをコマンド引数から指定
source = Scissor(ARGV[0])

# 小節で分割
#
#  1. Echo Nest に音声ファイルをアップロードし、解析結果をうけとる
#  2. 解析結果をもとにScissor インスタンスを分割する
#
# 解析結果は ~/.echonest/analysis/ 以下にキャッシュされ、次回以降はEcho Nest へのリクエストは行なわない
bars = source.bars

waltzified_bars = bars.map do |bar|
  # 小節を4 分割する
  b1, b2, b3, b4 = bar / 4

  # b1, b3 を引き伸ばす
  result = b1.stretch(200) + b2 + b3.stretch(200) + b4

  # テンポを調整する
  result.stretch(2.0 / 3.0 * 100)
end

# 保存
Scissor.join(waltzified_bars) >> 'waltzify.wav'

例: Scissor(+ Echo Nest API) で作ったもの

楽曲に合いの手を追加 (スクリプト)

コシミハル わがままな片想い + Mundo Musique - Acid Pandemonium (スクリプト)

Perfume の楽曲を分解してSND の楽曲構造にあてはめたもの (スクリプト)

sxy

sxy

まぁそれだけなんですが驚いたので紹介してみました。

enjoy!

Dan the beat chopper