DTM on Wine

はじめに

2020年の元日から7日に至るまで、

DTM 環境を NixOS (Linux)に構築する

と言うことをしていて、特に VST を Wine 上で動かすことについてかなりの知見を得られたので、 今回はその辺りの話をまとめて書いて行きたいと思います。

環境(2020年1月7日現在)

  • NixOS: linux kernel 4.19.92
  • Wine: 4.17-staging

基本的な流れ

  • 32bit の VST2 プラグインは airwave を使い 32bit 専用の WINEPREFIX を使う
  • 64bit の VST2 プラグインは linvst を利用し一つの WINEPREFIX にまとめる
  • 64bit の VST3 プラグインは linvst3 を利用し VST2 と同じ WINEPREFIX に入れる
  • VST2 の dll や VST3 の vst3 ファイルはインストール先をそれぞれ統一しておく

プラグインのインストール手順や workarounds

iLok による認証を要求するソフトウェア

まず前提として iLok によるライセンス認証を要求するソフトウェアは、 基本的に iLok のドングルによる認証が使えず、ソフトウェア認証だけで動作させる事になります。 と言うのもこの制約は、 iLok のドングルを Wine 経由で認識させる手段が無いために発生します。

またiLok の License Manager を動作させるためには、

  • ole32
  • oleaut32

の DLL Overrides が必要となると思われるのですが、 これらの Overrides が有効だと iLok のインストーラーがクラッシュするため、

  • iLok 関連ソフトウェアのインストール時には DLL Orverrides を無効に
  • iLok 関連のソフトウェアの利用時には DLL Overrides を有効に

と言う感じの 運用でカバー が発生します。

Native Instruments と Natve Access

まず Native Instruments の Native Access は dwrite が有効だと そもそも起動しない ため、 winecfg などで dwrite そのものを無効にします。

また Native Access を利用した Plugins のインストールは、 Native Access が ISO ファイルをマウントする形で Plugins をインストールする仕組みとなっているため、 Native Access を利用したインストールは ISO ファイルのダウンロード以外 すべて失敗します

そのため Native Instruments のプラグインは Native Access で ISO をダウンロードした後、 ISOファイルの中身をすべて展開した上で それぞれ個別に WINEPREFIX にインストールし、 その後で Native Access を起動してライセンス認証を有効にする、と言う手段を取ります。

なおこの際に ISOファイルの中身をすべて展開する必要がある のは、 そうしないと そもそも Native Instruments プラグインのインストーラーが起動しないため です。

また最後に Native Access の使用が一段落したら、 今度は Native Access を利用する際に無効化した dwrite の設定を元に戻しておきましょう。 と言うのも、dwrite が無効だと動作しない他のVST プラグインも存在し得るからです。

KORG Gadgets

KORG Gadgets for Windows はインストールすればほぼそのまま動作しますが、 一点、ライセンス認証のみ注意が必要です。

と言うのも、KORG Gadgets はライセンス認証時にブラウザからオレオレプロトコルな URL を開き、 その URL 経由で認証アプリケーションを立ち上げてライセンス認証を行うと言う、 スマートフォンなどでのアプリケーション専用 URI Schema を利用した認証方法を採用しているためです。

そのため、KORG Gadgets のライセンス認証を通すためには、

  1. KORG Gadgets のプラグインを立ち上げてライセンス認証画面を出す
  2. ライセンス認証画面からブラウザを開き、Network Inspector を表示する
  3. Network Inspector を開いた状態で KORG にログインしリダイレクト先 URL をメモ
  4. GadgetAuthorizer.exe を先のURLを引数にして起動
  5. その後ライセンス認証画面が推移するのでシリアルを入力して認証させる

と言う手順が必要となります。面倒ですね。

IK Mulitmedia

基本的にインストールすればほぼそのまま動きますが、Sample Tank 4 などは実機と同じく、

  • ライブラリのダウンロードが死
  • ライブラリのインストール作業も死
  • ライブラリのインストール先の容量が大量に要求されて死

などと言った点から 使える様になるまでがクッソめんどい ので、 時間などに余裕を持って行わないと後で死にます。

あとこれは要調査事項なのですが、 Sample Tank 4 の場合 CPU負荷が低いのに音割れが起きた時もあったので、 もしかするとマルチコアが上手く使えていない、などのトラブルも起き易いのかもしれません。

DAW でプラグインを利用する際の注意

Bitwig Studio

なんか Bitwig Studio 3.1.1 時点での実装の加減なのか、

KORG や IK Multimedia が読み込むとGUI が出ずにプラグインがフリーズする

と言う事態が linvst でも airwave でも良く起きるため、基本的に自分はこれに対して、

Bitwig Studio では Carla と言う Plugin Host を経由して VST on Wine を使う

と言う事をやっています。そのため Bitwig Studio を使う際には、 Jack Audio Connection Kit でのルーティングが必須になってます。

Carla での注意点

たぶんこれもプラグインに依ると思うのですが、Carla で VST on Wine を鳴らす際、 なぜか airwave だと音割れしたんで、自分は 32bit プラグイン以外は基本的に linvst を使ってます。はい。

あと細かい話

Makefile と Perl Script

VST on Wine をする際に、手作業でプラグインを使える様にするのは流石に面倒だったので、 自分は下記の様な Makefile と Perl Script で作業を自動化しています。

ただこれらのファイルは自分の環境専用なので、利用の際には各自でアレンジしてください:

.PHONY: vst vst3

all: vst vst3

vst:
	rm -rf ~/local/vst
	mkdir -p ~/local/vst
	perl scripts/airwave.pl >~/.config/airwave/airwave.conf
	cd 'DTM64/drive_c/Program Files/Common Files/VST2' \
		&& chmod +w -R . \
		| find . -type f -name '*.dll' \
		| xargs -I{} bash -c 'cp /run/current-system/sw/lib/vst/linvst.so "$$(echo "{}" | sed "s!\.dll!\.so!")"'

vst3:
	cd 'DTM64/drive_c/Program Files/Common Files/VST3' \
		&& chmod +w -R . \
		| find . -type f -name '*.vst3' \
		| xargs -I{} bash -c 'cp /run/current-system/sw/lib/vst/linvst3.so "$$(echo "{}" | sed "s!\.vst3!\.so!")"'
#!/usr/bin/env perl

use strict;
use warnings;
use utf8;

use JSON;

my $airwave = `bash -c 'echo -n \$(nix-store -r \$(nix-store -qd \$(which airwave-manager)))'`;
chomp($airwave);

my $wine = `bash -c 'echo -n \$(nix-store -r \$(nix-store -qd \$(which wine64)))'`;
chomp($wine);

my $libexec   = "${airwave}/libexec";
my $log_level = 2;
my $log_sock  = "/tmp/airwave.sock";
my $links     = [];
my $loaders   = [
  { name => "wine64",
    path => "${wine}/bin/wine64",
  }
];
my $prefixes     = [
  { name => "DTM",
    path => "/run/media/nyarla/LINUX/Wine/DTM32/",
  },
# { name => "DTM64",
#   path => "/run/media/nyarla/LINUX/Wine/DTM64/",
# },
];

for my $prefix ( $prefixes->@* ) {
  my $path = $prefix->{'path'};

  for my $file (`find '${path}drive_c/Program Files/Common Files/VST2' -type f -name '*.dll'`) {
    chomp($file);
    $file =~ s{^$path}{};

    my $vst = "/home/nyarla/local/vst/@{[ ($file =~ m{/([^/]+?).dll$})[0] ]}.so";
    
    `cp '${libexec}/airwave-plugin.so' '$vst'`;

    push $links->@*, {
      loader    => ( $prefix->{'name'} =~ m{64} ? 'wine64' : 'default' ),
      log_level => -1,
      path      => $vst,
      prefix    => $prefix->{'name'},
      target    => $file,
    };
  }
}

print JSON::encode_json({
  binaries_path     => $libexec,
  default_log_level => $log_level,
  links             => $links,
  loaders           => $loaders,
  log_socket_path   => $log_sock,
  prefixes          => $prefixes,
});

linvstlinvst3airwave のパッケージ定義ファイル

nyarla/nixos-configurations: My configuration.nix files for NixOS

My configuration.nix files for NixOS. Contribute to nyarla/nixos-confi...

https://github.com/nyarla/nixos-configurations

上記 GitHub リポジトリにも含まれているのでそちらからでも閲覧可能ですが、 一応ここでも定義ファイルを掲載しておきます:

{ multiStdenv, fetchurl, wineWowPackages, xorg, gnused }:
multiStdenv.mkDerivation rec {
  name = "linvst";
  version = "git";

  src     = fetchurl {
    url = "https://github.com/osxmidi/LinVst/archive/master.tar.gz";
    sha256 = "14w24avlfy03zfw3d0v3c7qc0a37zzd89pi021aqdaf76mx5fyza";
  };
  
  nativeBuildInputs = [
    wineWowPackages.staging gnused
  ];

  buildInputs = [
    xorg.libX11
  ];

  patchPhase = ''
    rm Makefile
    mv Makefile-embed-6432 Makefile
    sed -i "s!/usr!$out!" Makefile
    sed -i "s!./vst!$out/lib/vst!" Makefile
    sed -i "s!/usr/lib/x86_64-linux-gnu/wine-development!${wineWowPackages.staging}/include/wine!" Makefile
    sed -i "s!/usr/bin!$out/bin!g" remotevstclient.cpp
  '';
}

{ stdenv, fetchurl, fetchgit, pkgconfig, gnused, gnutar, cmake,
freetype, fontconfig, xorg, cairo, gtkmm3, libxkbcommon, sqlite, libxcb, pcre, glib,
utillinux, libselinux, libsepol, epoxy, libjack2, atk, at-spi2-core, dbus, wineWowPackages }:
let
  vst3sdk = fetchgit {
    url = "https://github.com/steinbergmedia/vst3sdk";
    fetchSubmodules = true;
    sha256 = "0hqg5fl4xbrml4kr4mgbxxk8hnhags0f5lwb0m17nbajbksgan58";
  };
in stdenv.mkDerivation rec {
  name = "linvst3";
  version = "1.8";
  src = fetchurl {
    url = "https://github.com/osxmidi/LinVst3/archive/1.8.tar.gz";
    sha256 = "157pikv8am2b6xdpjpp4yczqgc6a4dpssmvq3f7r6181n4c53mff";
  };
  
  buildInputs = [
    freetype libxkbcommon gtkmm3 sqlite fontconfig cairo wineWowPackages.staging atk.dev at-spi2-core.dev
    libxcb pcre glib.dev libjack2 utillinux.dev libselinux libsepol epoxy dbus.dev
  ] ++ (with xorg; [
    libX11 xcbutil xcbutilcursor xcbutilimage xcbutilerrors
    xcbutilkeysyms libpthreadstubs
    libXdmcp xcbutilrenderutil
    libXtst
  ]);

  dontUseCmakeConfigure = true;
  
  unpackPhase = ''
    cp -R ${vst3sdk} vst3sdk
    chmod -R +w vst3sdk
    tar -zxvf ${src} -C .
    mv LinVst3-1.8 vst3sdk/LinVST3
    cd vst3sdk/LinVST3
  '';

  nativeBuildInputs = [ gnused cmake pkgconfig ];
  
  patchPhase = ''
    sed -i "s!/usr!$out!" Makefile
    sed -i "s!./vst!$out/lib/vst!" Makefile
    sed -i "s!/usr/lib/x86_64-linux-gnu/wine-development!${wineWowPackages.staging}/include/wine!" Makefile
    sed -i "s!/usr/include/wine-development!${wineWowPackages.staging}/include/wine!g" lin-patchwin
    sed -i "s!/usr/bin/wine!${wineWowPackages.staging}/bin/wine!g" lin-patchwin
    sed -i "s!/usr/bin!$out/bin!g" remotevstclient.cpp
    sed -i 's!file(MAKE_DIRECTORY ''${SMTG_PLUGIN_TARGET_PATH})!!' ../cmake/modules/AddVST3Options.cmake
    sed -i 's!/bin/bash!${stdenv.shell}!' ../vstgui4/vstgui/uidescription/editing/createuidescdata.sh
    sed -i 's!#include <processthreadsapi.h>!!' ../public.sdk/source/common/threadchecker_win32.cpp
  '';
}
{ multiStdenv, fetchurl, fetchzip, cmake, makeWrapper, file, xorg, qt5, wineWowPackages }:
let
  vst2sdk = fetchzip {
    url = "https://archive.org/download/VST2SDK/vst_sdk2_4_rev2.zip";
    sha256 = "1x4qfviwcssk4fswhqks745jicblpy352kd69p7cqmgfcxhckq79";
  };
in multiStdenv.mkDerivation rec {
  version = "git";
  name = "airwave-${version}";
  src = fetchurl {
    url = "https://github.com/psycha0s/airwave/archive/master.tar.gz";
    sha256 = "1br95fcjkf0jimlyl7w9lqnzqrkynpcyzymb5licmn8p5cmgmpr5";
  };

  buildInputs = [
    cmake makeWrapper
  ];

  nativeBuildInputs = [
    file xorg.libX11 qt5.qtbase wineWowPackages.staging
  ];
   
  postPatch = ''
    substituteInPlace src/common/storage.cpp --replace '"/bin"' '"/libexec"'
    substituteInPlace src/host/CMakeLists.txt --replace '-m32' \
      '-m32 -L${wineWowPackages.staging}/lib -L${wineWowPackages.staging}/lib/wine -L${multiStdenv.cc.libc.out}/lib/32'
  '';

  dontPatchELF = true;

  hardeningDisable = [ "format" ];

  cmakeFlags = "-DVSTSDK_PATH=${vst2sdk}";

  postInstall = ''
    mv $out/bin $out/libexec
    mkdir $out/bin
    mv $out/libexec/airwave-manager $out/bin
    wrapProgram $out/libexec/airwave-host-32.exe --set WINELOADER ${wineWowPackages.staging}/bin/wine
    wrapProgram $out/libexec/airwave-host-64.exe --set WINELOADER ${wineWowPackages.staging}/bin/wine64
  '';

}

nyarla が大体に記述

Scrapbox でコメントや意見を書く