Chasm of the Apocalypse

I am aware it is indeed quite a boring / droning track but as my first foray into audio synthesis, it will do for now. Using Paulstretch Mono algorithm as a starting point, here is the Chuck code I used to generate that garbage:

SndBuf  buff => FFT fft =^ IFFT ifft => blackhole;
Impulse imp => LPF lpf => blackhole;
dac => WvOut w => blackhole;
lpf => PitShift ps1 => dac;
lpf => PitShift ps2 => dac;
lpf => PitShift ps3 => dac;

1000 => lpf.freq;
0.25 => ps1.shift;
0.5 => ps1.gain;
2 => ps2.shift;
0.8 => ps2.gain;
0.125 => ps3.shift;
0.5 => ps3.gain;

30.0 => float stretch;
5::second => dur window_dur;

me.sourceDir() + "/cc.wav" => string filename;
buff.read(filename);
buff.samples() / (buff.length() / 1::second) => float sample_rate;

me.sourceDir() + "/output_cc.wav" => w.wavFilename;

((window_dur / 1::second) * sample_rate) $ int => int window_size;
(window_size / 2) $ int => int half_window_size;

window_size => fft.size;
Windowing.hann(window_size) => fft.window;
Windowing.hann(window_size) => ifft.window;

complex s[half_window_size];
float ifft_s[window_size];
float old_ifft_s[half_window_size];

(1+Math.sqrt(0.5))*0.5 => float hinv_sqrt2;
float hinv_buf[half_window_size];
for(int i; i < half_window_size; i++) {
    hinv_sqrt2-(1.0-hinv_sqrt2)*Math.cos(i*2.0*pi/half_window_size) => hinv_buf[i];
}

0 => int start_pos;
(half_window_size / stretch) $ int => int displace_pos;

// control loop
while( start_pos < buff.samples())
{
    start_pos => buff.pos;

    fft.upchuck();
    fft.spectrum(s);
    polar pol;
    for(int i; i< window_size;i++) {
        s[i] $ polar => pol;
        Math.random2f(0, 2 * pi) => pol.phase;
        pol $ complex => s[i];
    }
    ifft.transform(s);
    ifft.samples(ifft_s);

    float output;
    for(int i; i < half_window_size ; i++) {
        hinv_buf[i] * (ifft_s[i] + old_ifft_s[i]) => output;
        ifft_s[i+half_window_size] => old_ifft_s[i];
        if(output > 1.0) {
            1.0 => output;
        } else if(output < -1.0) {
            -1.0 => output;
        }
        output => imp.next;
        1::samp => now;
    }

    displace_pos +=> start_pos;
}

There needs to be an input file named “cc.wav” in the same directory as the .ck file (for my track, I used the song “Creataceous Chasm” by Blotted Science). An output Wav file can be obtained with the command:

chuck --silent stretch_simple.ck

(Unfortunately, my stretch algorithm produces audible clicks in real-time mode so “–silent” must be used)

For contrast, here is a video for the Blotted Science song used as input:

Automating iTunes on Windows with IronRuby

I recently bought a new Windows computer and, since there is no AppleScript on Windows, I have to do without the Doug’s scripts for ITunes that I used on Mac OS X to automate the management of my music library. But Apple has made available a COM API, that can be used by any language to script iTunes, as long as it supports COM. This includes Ruby MRI, with the Win32OLE package in the standard library. But I was curious about IronRuby, the .NET implementation of Ruby, which recently reached version 1.0 and therefore, I decided to reimplement with it some of the scripts I used the most.

The scripts shown in this post can be downloaded here.

Installing IronRuby

The PATH environment variable is updated and now contains the “ir.exe” executable.

Connecting to the iTunes COM object

Since this functionality is going to be used by all the scripts, I extracted it in a separate file called “iTunesLib.rb” :


module ITunes
  def self.app
    begin
      itunes_type = System::Type.get_type_from_prog_i_d("iTunes.Application")
      itunes = System::Activator.create_instance(itunes_type)
      yield itunes
    rescue Exception => e
      puts e
    end
  end
end

This modules hides all the COM plumbing from the scripts. It uses the standard .NET libraries to interface with COM: For example, by using the System.Activator class. One nice thing IronRuby does is to allow the use of rubyfied names for methods, using undescores. It is still possible to use the original .NET names though.

Prefix to track number

The first script is very simple: All it does is check if the “Song” fields of the tracks currently selected in iTunes begin with a number, and if they do, copy this number to the “Track Number” field: “07 – Hypersurface” will have track number 7.


require "iTunesLib"

ITunes.app do |itunes|
  sels = itunes.selected_tracks

  if sels.nil?
    puts "No selection"
    break
  end

  1.upto(sels.count) do |i|
    track = sels.item(i)
    if track.name =~ /^\s*(\d+)/
      track.track_number = $1.to_i
    end
  end
end

After selecting some tracks with the iTunes interface, the script can be run on the command line like this (no arguments are necessary):

ir.exe prefix_to_track_number.rb

(Note: This really modifies the tracks. No undo is possible…)

Remove n characters from front or back

This script removes an arbitrary number of characters, from the front and/or back of either the “Artist”, “Album” or “Song” field. At the beginning, there are various checks of the arguments, followed by the main code, which loops through the tracks currently selected in iTunes. Update: Added checks for the field inside the loop


require "iTunesLib"

if ARGV.length <= 1
  puts "Usage: #{__FILE__} [a|l|n] [<f or b> <num chars to remove>]+"
  puts "a => artist, l => album, n => song name"
  exit
end

scope = ARGV.shift
if scope !~ /a|l|n/
  puts "Bad scope"
  exit
end

rff = nil
rfb = nil

ARGV.each_with_index do |a,i|
  if a == "f"
    rff = ARGV[i + 1].to_i if i < ARGV.length - 1
  elsif a == "b"
    rfb = ARGV[i + 1].to_i if i < ARGV.length - 1
  end
end

if rff.nil? and rfb.nil?
  puts "Nothing to do"
  exit
end

ITunes.app do |itunes|
  sels = itunes.selected_tracks

  if sels.nil?
    puts "No selection"
    break
  end

  1.upto(sels.count) do |i|
    track = sels.item(i)

    if scope == "n"
      name = track.name
    elsif scope == "l"
      name = track.album
    else
      name = track.artist
    end

    if !rff.nil?
      #name is an immutable .NET string
      name = name.slice(rff..-1)
    end

    if !rfb.nil?
      name = name.slice(0..-(rfb+1))
    end

    if scope == "n"
      track.name = name
    elsif scope == "l"
      track.album = name
    else
      track.artist = name
    end
  end
end

One of the only gotchas I encountered with IronRuby had to do with the fact that .NET strings are immutable. But in Ruby, strings are mutable and there are methods ending with “!” (such as “slice!”) that can be used to modify the current String instance instead of returning a new one. Those methods cannot be used on .NET/CLR strings (that are returned by the methods of .NET objects). This is why I used “name = name.slice” instead of something like “name.slice!” in the code above. I later learned that the “to_s” method could have been used on a .NET string to obtain a Ruby string.

After selecting some tracks with the iTunes interface, the script can be run on the command line like this:

ir.exe remove_n_characters_from_front_or_back.rb n f 5

(“n” means the “Song” field; “f” means the front of the field; “5” the number of characters to remove)

Using the previous song name example: “07 – Hypersurface” will become “Hypersurface”.

Bonus

You have read the complete article! Here is a great track as a reward:

Dopplereffekt – Z-Boson (from “Linear Accelerator“)