いい感じの曲のつくりかた

この記事は CCS Advent Calendar 2017 11日目の記事です。
昨日は、@LuCK_ver_2 さんの 第二回目LuCKの不思議空間 でした。

おはようございます。CCS OBのりょいと申します。

去年なんとなく作ったCCSアドベントカレンダーを今年もやるということで、
今年はCCSっぽく曲の作り方を書いてみたいと思います。

曲を用意しました

説明用に曲を作りました。微妙とかいわないで。

テーマを決める

まずは何が作りたいのかを明確にします。
雰囲気とか、BGMなら流れる場面とか。

楽器が弾ける人は、適当に手癖で弾いてみて出たフレーズからイメージを固めるのもアリです。自分もよくやります。

今回は、

  • ゲームのBGM
  • シューティングとかアクションとかステージがある系
  • 道中

みたいなイメージで作ります。
ジャンルとかは全く決めずに作り始めました。

コードを作る

ここから人によってバラバラだと思いますが、自分は先にコードを作ります。
コードを作っておくと調が決まるので、メロディとかを弾きやすくなるからです。

自分の場合はコードは完全に鍵盤で弾いて作ります。頭の中ではっきり音がなる人はその通りに打ち込めばいいんですが、
自分は残念ながらそういう人間ではないので、手でごちゃごちゃやります。

コードが決まると曲のジャンルとか雰囲気がある程度決まります。
BPMもこのあたりで決めることが多いです。

メロディを作る

コードが決まると鳴らせる音がほぼ決まるので、流れに任せてメロディを作ります。
ここで最終版を作りこむというよりはさらっと作ってしまいます。
もちろんいいものができたらそれはそれでラッキーです。

リズムの骨格を作る

まずはマルチ音源のドラムキットを読み込んで適当に叩きます。
(今回はXpand!2を使いました。)
そして、音色をぱちぱち切り替えて雰囲気に合うものを探します。

最初から音作りとかを始めてしまうと全く進まないので最初は雰囲気さえ合っていればOKという発想です。

ベースを作る

ベースラインはどうやって作ったらいいのか教えて欲しい……

自分はコード、メロディとは違い頭の中で鳴らしてから手を動かすことが多いです。

全く動かずルートをなぞるのか、ひたすら動かすのか、どちらの方針で行くのかは決めた方がいいと思います。

リズムを作る

ベースができたらリズムをちゃんとつくり込みます。

ここが超大事なんですが、まずサンプルパックのループを貼り付けます
めちゃめちゃ凝ったリズムをつくりたい場合は1から作った方が早いですが、大抵はまず貼ってみた方が即いい感じになるのでオススメです。

音色の雰囲気が決まったらBattery等のサンプラーで音を作ります。
これ以降いじらない勢いで、レイヤーしたりピッチいじったりコンプかけたりしていい感じのノリを作ります。
今回はキック2つスネア2つとループ1つとサンプル1つを使いました。

裏のシーケンスを作る

聞こえづらいのでメロディなしバージョンも用意しました。

SAW系の音とベル系の音の2つを足しています。
あまり表には出てこない音ですが、メインのメロディと同じくらい重要だと思います。
これがあることでメロディが前に出てきます。

ここを作るにはインプットが大事なので、お気に入りの曲を耳を凝らして何回も聞きましょう。

メロディを作り直す

案の定メロディが気に入らなくなったのでボツにしました。

これも適当に手癖で弾いてつくりました。

コードを作り直す

メロディを変えたらコードと合わなくなった場所がでてしまったので直します。

具体的に言うと4小節目のDで、メロディのf,a#とコードのf#,aがぶつかっていて濁って聞こえてしまうのでFに変えました。
ちなみに16小節目は展開部分が平行調へ転調しているのでつなぎでD7になっています。

いろいろ音を足す

↓メロディなしバージョンです。

ストリングスっぽいシンセとか8小節目16小節目のマレット系の音とかスネアロールとかいろいろ足しました。
このあたりも他の曲を参考にしたりします。

展開部分をつくる

展開部分のコードは最初に一緒に作っていたので、それ以降の工程を同様にやるだけなので省略。
wav書き出すのが面倒だったというわけでは決してないです

ミックスとかいろいろ調整

EQとかコンプとかいろいろ駆使していい感じに混ぜます。
やり方はYoutubeのハウツー動画とかハウツーサイトを探してください。
自分もわかりません。

とりあえず倍音を足しておくと手っ取り早くいい感じになります。
SSLをエミュレーションしたEQとかサチュレーターとかをバンバン刺しましょう。
(刺しすぎると音がモコモコするので適度に)

あと一回モノラルにして聞いてみるとバランス調整に役立ちます。
ステレオだと気にならないけどモノラルで聞いてみるとメロとかスネアが超大きかったりします。

最近マスターに刺しているエフェクトはOTTとAddictive Limiterです。
Addictive LimiterはLogicでないと使えませんが、Xfer Records OTTはフリーなのでぜひ使ってみてください。
バキバキに潰れて倍音足しまくりで一気に今風の音になります。

完成

という感じで自分は作っていますという紹介記事でした。

なにかしら参考になれば幸いです。

あー!冬コミの締め切りがやばい!!!

明日 12日目の記事は @sirius114514 さんです。

DTVに最適なコンテナフォーマット

この記事は DTV Advent Calendar 2016 19日目の記事です。

日本の地上デジタル放送や BS/CS デジタル放送は、基本的に MPEG-2 TS と呼ばれるコンテナフォーマットで多重化されたデータを放送しています。
MPEG-2 TS はストリーミングに最適化されており、ノンリニアに編集したり、保存して視聴するには適さないフォーマットです。
この記事では、そんな MPEG-2 TS をどのようなフォーマットに変換すれば便利に扱えるかを考えようというお話をします。

なぜ TS のままだとダメなのか

  • 取り扱いがだるい
    そのまま変換しようとすると、ほぼ確実に映像と音声がズレます。
  • 再生がつらい
    最近は減りましたが、正しく再生できないプレイヤーがありました。
    特に iOS/Android 上のプレイヤーに多かった印象があります。
  • 機能が足りない
    個人的にはこれが一番大きいです。
    MPEG-2 TS には、チャプターを挿入する機能がありません。
    放送にチャプターもクソもないので、ついていないのは当たり前といえば当たり前なんですが。

いいコンテナフォーマットを探す

前述の問題を解決するために、いろいろなフォーマットを調べてどれがいいのか比べてみました。

MPEG-2 PS

ほぼ TS と同じなので、変換に手間取ることはありません。PS に変換すると、TS 特有の番組表や有料放送用のデータが落ちるため、ファイルサイズが小さくなります。DVD 等にも用いられている MPEG-2 PS ですが、チャプターを挿入する機能がありません。個人的にはこれだけで比較対象から外れるのですが、何か理由があるのでしょうか。

ちなみに BonTsDemux で エンコード方式を MPEG2PS にして変換すると、ffmpeg により音声が再エンコードされてしまうので、demux してからなんらかの muxer を用いて mux するといいと思います。

Matroska

Matroska とは公式サイトによると、

Matroska the extensible, open source, open standard Multimedia container.

だそうです。

最近はサブセットの WebM が有名ですが、本体の方はいまいち流行ってません。入れられるコーデックは、Codec Specs に書かれており、主要なものは一通り揃っています。機能的にも問題はなさそうです。

MP4

安定の MPEG4 です。みんな大好き H.264 も同じ MPEG-4 の Part 10 として標準化されています。機能は多く、H.264 と合わせて現在最も利用されているフォーマットだと思います。
H.264 と一緒に使われることが多い MP4 ですが、実は MPEG-2 を入れることもできます。したがって、TS から再エンコードすることなく MP4 を利用することもできてしまうのです。

MP4 で mux するには MP4Box を利用します。BonTsDemux で demux したあと、MP4Box で mux するという流れになるのですが、BonTsDemux から出力された音声ファイルはズレているため、補正する必要があります。BonTsDemux で出力した音声ファイルのファイル名に付加されるDELAY *msが遅延時間となります。経験則では、音声が数百ms早いことが多いようで、DELAY -100msというように出力されます。この情報を MP4Box に渡してあげる必要があるのですが、そのまま音声を早めるように処理させると頭に無音で真っ暗な部分が生じてしまいます。この挙動が仕様と実装のどちらによるものなのかは分かりませんが、映像のみで音声がないことは許され、音声のみで映像がないことは許されないようです。したがって BonTsDemux が出力した遅延時間の正負を反転させ、映像を遅らせるようにするとうまく処理されます。

$ MP4Box.exe -fps 29.97002997002997 -add "[映像ファイル名].m2v"#video:par=4:3:delay=[遅延ms] -add "[音声ファイル名].aac"#audio -chap "[チャプターファイル名].txt" -new "[出力ファイル名].mpg"

たどり着いた結果

  1. TsSplitter でいらないデータを落とす
  2. BonTsDemux で TS を m2v と aac に demux
  3. m2v を元に logoGuillo で CM 検出し、.chapters.txt を生成
  4. MP4Box で m2v, aac, .chapters.txt を mux

録画マシンのスペックが低いためこのような形になりました。

まとめ

いかがでしたでしょうか。
結局 MP4 に入れてしまいましょうという普通の結論になってしまいましたが、録画マシン運用の参考になれば幸いです。

DTV Advent Calendar 2016 20 日目の記事は kanreisa さんです。

SECCON 2016 オンライン予選

軽い感じで参加してみました。400 点で提出 930 チーム中 286 位という結果でした。

Vigenere

問題文を読んでヴィジュネル暗号についてググってプログラミングするだけ。

まずSECCON{に対応するキーの先頭7文字を求めておきます。
するとキーは少なくともVIGENER?????であることが分かります。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
#!/usr/bin/env perl

use strict;
use warnings;
use Digest::MD5;

my $md5 = Digest::MD5->new;

my @cipher = split(//,"LMIG}RPEDOEEWKJIQIWKJWMNDTSR}TFVUFWYOCBAJBQ");
my %dic = (
'A' => 0,
'B' => 1,
'C' => 2,
'D' => 3,
'E' => 4,
'F' => 5,
'G' => 6,
'H' => 7,
'I' => 8,
'J' => 9,
'K' => 10,
'L' => 11,
'M' => 12,
'N' => 13,
'O' => 14,
'P' => 15,
'Q' => 16,
'R' => 17,
'S' => 18,
'T' => 19,
'U' => 20,
'V' => 21,
'W' => 22,
'X' => 23,
'Y' => 24,
'Z' => 25,
'{' => 26,
'}' => 27,
);
my @key = split(//,'VIGENEREAAAA');
my @next = split(//,'BCDEFGHIJKLMNOPQRSTUVWXYZ{}A');

my %table;
my @A = split(//,'ABCDEFGHIJKLMNOPQRSTUVWXYZ{}');
$table{'A'} = \@A;
my @B = split(//,'BCDEFGHIJKLMNOPQRSTUVWXYZ{}A');
$table{'B'} = \@B;
my @C = split(//,'CDEFGHIJKLMNOPQRSTUVWXYZ{}AB');
$table{'C'} = \@C;
my @D = split(//,'DEFGHIJKLMNOPQRSTUVWXYZ{}ABC');
$table{'D'} = \@D;
my @E = split(//,'EFGHIJKLMNOPQRSTUVWXYZ{}ABCD');
$table{'E'} = \@E;
my @F = split(//,'FGHIJKLMNOPQRSTUVWXYZ{}ABCDE');
$table{'F'} = \@F;
my @G = split(//,'GHIJKLMNOPQRSTUVWXYZ{}ABCDEF');
$table{'G'} = \@G;
my @H = split(//,'HIJKLMNOPQRSTUVWXYZ{}ABCDEFG');
$table{'H'} = \@H;
my @I = split(//,'IJKLMNOPQRSTUVWXYZ{}ABCDEFGH');
$table{'I'} = \@I;
my @J = split(//,'JKLMNOPQRSTUVWXYZ{}ABCDEFGHI');
$table{'J'} = \@J;
my @K = split(//,'KLMNOPQRSTUVWXYZ{}ABCDEFGHIJ');
$table{'K'} = \@K;
my @L = split(//,'LMNOPQRSTUVWXYZ{}ABCDEFGHIJK');
$table{'L'} = \@L;
my @M = split(//,'MNOPQRSTUVWXYZ{}ABCDEFGHIJKL');
$table{'M'} = \@M;
my @N = split(//,'NOPQRSTUVWXYZ{}ABCDEFGHIJKLM');
$table{'N'} = \@N;
my @O = split(//,'OPQRSTUVWXYZ{}ABCDEFGHIJKLMN');
$table{'O'} = \@O;
my @P = split(//,'PQRSTUVWXYZ{}ABCDEFGHIJKLMNO');
$table{'P'} = \@P;
my @Q = split(//,'QRSTUVWXYZ{}ABCDEFGHIJKLMNOP');
$table{'Q'} = \@Q;
my @R = split(//,'RSTUVWXYZ{}ABCDEFGHIJKLMNOPQ');
$table{'R'} = \@R;
my @S = split(//,'STUVWXYZ{}ABCDEFGHIJKLMNOPQR');
$table{'S'} = \@S;
my @T = split(//,'TUVWXYZ{}ABCDEFGHIJKLMNOPQRS');
$table{'T'} = \@T;
my @U = split(//,'UVWXYZ{}ABCDEFGHIJKLMNOPQRST');
$table{'U'} = \@U;
my @V = split(//,'VWXYZ{}ABCDEFGHIJKLMNOPQRSTU');
$table{'V'} = \@V;
my @W = split(//,'WXYZ{}ABCDEFGHIJKLMNOPQRSTUV');
$table{'W'} = \@W;
my @X = split(//,'XYZ{}ABCDEFGHIJKLMNOPQRSTUVW');
$table{'X'} = \@X;
my @Y = split(//,'YZ{}ABCDEFGHIJKLMNOPQRSTUVWX');
$table{'Y'} = \@Y;
my @Z = split(//,'Z{}ABCDEFGHIJKLMNOPQRSTUVWXY');
$table{'Z'} = \@Z;
my @bra1 = split(//,'{}ABCDEFGHIJKLMNOPQRSTUVWXYZ');
$table{'{'} = \@bra1;
my @bra2 = split(//,'}ABCDEFGHIJKLMNOPQRSTUVWXYZ{');
$table{'}'} = \@bra2;

while(1) {
print join("", @key),"\n";
my $buf = "";
for (my $i = 0; $i < @cipher; $i++) {
my $ni = $i % 12;
my @t = @{$table{$key[$ni]}};
for (my $j = 0; $j < @t; $j++) {
if ($t[$j] eq $cipher[$i]) {
foreach (keys %dic) {
if ($dic{$_} == $j) {
$buf .= $_;
last;
}
}
last;
}
}
}
my $h = $md5->add($buf)->hexdigest;
if ($h eq 'f528a6ab914c1ecf856a1d93103948fe') {
print $buf,"\n";
exit;
}
$key[11] = $next[$dic{$key[11]}];
if ($key[11] eq 'A') {
$key[10] = $next[$dic{$key[10]}];
if ($key[10] eq 'A') {
$key[9] = $next[$dic{$key[9]}];
if ($key[9] eq 'A') {
$key[8] = $next[$dic{$key[8]}];
if ($key[8] eq 'A') {
$key[7] = $next[$dic{$key[7]}];
}
}
}
}
}

我ながら酷いコードですね。
while文の中がメインの探索部で、最初のforで復号、MD5 を取って正解チェック、違ったら次のキーへ、という処理を回しています。単純なブルートフォースです。
最初は完全に確定しているVIGENERまでを固定しておいて回したんですが、終わりそうになかったので推測でVIGENEREと埋めて回したら1分くらいですぐ見つかりました。

VoIP

とりあえず Wireshark で開いて、全パケットを結合しないといけないの?と思いながらググったところ、Wireshark に VoIP パケットを再生できる機能があることが分かりました。
電話(y)VoIP通話(V)ストリームを再生で再生できます。
これで再生はできたんですがシークする機能がないようで、自分の英語力では一発で聞き取れなくてかなり厳しかったので、Soundflower と Audacity でさくっと録音して繰り返し聴いてなんとかなりました。
DTM やっててよかった!あと英語力大事!

Memory Analysis

説明に書いてある通り、ダウンロードしたファイルを Volatility Framework に入れてごちゃごちゃします。

「Volatility Frameworkを使ったメモリフォレンジック」と言うハンズオンに参加させて頂きました。 | Developers.IO

このサイトがめちゃくちゃ参考になりました。

まずimageinfoでOSを特定し、pstreeで起動しているプロセス一覧を取得、connectionsconnscanで接続先を取得するところまでは上のサイト通りにやりました。

いまいち正確な解答がわかっていないのですが、
結局hostsを抽出し、IEの履歴を見てそのURLにhostsが適用されているものとしてアクセスする、すなわちhttp://153.127.200.178/entry/Data-Science-import-pandas-as-pdにアクセスするとフラグが取れます。
説明にWebサイトにアクセスすればフラグが取れますと追記されたのが逆に悩む元になって、crattack.tistory.com の中をくまなく探したりしてしまいました。
crattack.tistory.com のアクセスカウンタがどんどん回っているのがとにかく気になって仕方がなかったです。

$ vol.py -f forensic_100.raw --profile=WinXPSP2x86 filescan | grep hosts
Volatility Foundation Volatility Framework 2.5
0x000000000217b748 1 0 R--rw- \Device\HarddiskVolume1\WINDOWS\system32\drivers\etc\hosts
------------------------------------------------------------
$ vol.py -f forensic_100.raw --profile=WinXPSP2x86 dumpfiles -D output2/ -Q 0x000000000217b748
Volatility Foundation Volatility Framework 2.5
DataSectionObject 0x0217b748 None \Device\HarddiskVolume1\WINDOWS\system32\drivers\etc\hosts
$ vol.py -f forensic_100.raw --profile=WinXPSP2x86 iehistory
Volatility Foundation Volatility Framework 2.5
(省略)
**************************************************
Process: 380 IEXPLORE.EXE
Cache type "URL " at 0x76be00
Record length: 0x180
Location: http://crattack.tistory.com/entry/Data-Science-import-pandas-as-pd
Last modified: 2016-12-06 03:39:11 UTC+0000
Last accessed: 2016-12-06 05:28:40 UTC+0000
File Offset: 0x180, Data Offset: 0xac, Data Length: 0xd0
File: Data-Science-import-pandas-as-pd[1]
Data: HTTP/1.1 200 OK
Content-Type: application/octet-stream
Content-Length: 42
ETag: "584632df-2a"

~U:system
**************************************************
(省略)

Anti-Debugging

まず手元に CPU が Atom のへっぽこ Windows マシンしかなくて解こうか迷ったんですが、他に解けそうな問題が見当たらなかったので挑戦してみました。

問題名からデバッガが必要なんだろうなと思い、とりあえず Mac だけでなんとかならないか足掻いてみようと IDA というデバッガを Wine で実行してみたんですが、なんかうまく動きそうになかったので Mac でやるのは早々に断念。

次に Windows に移動して、Immunity Debugger というデバッガで実行。

まず正しいパスワードがわからなくて困ったんですが、Mac でstringsコマンドに通してみたところ、出力されているメッセージのあたりにI have a pen.という文字列があったのでこれを入力してみたところYour password is correct.となったのでパスワードを発見。
そのついでに、あきらかに何かしらの暗号化が施されている文字列;aj&@:JQ7HBOt[h?U8aCBk]OaI38"が見え、これをどうにかしたら復号できるんじゃないかとも思いましたが、まじめにアンチデバッギングを一つ一つ処理しました。

しかし、CheckRemoteDebuggerPresentをスキップさせるために試行錯誤しているあたりで、アンチデバッギング対策なんてチートの必須技術なんだから何かツールがあるんじゃないかと思いググったところ ScyllaHide というツールを発見。
ScyllaHide は、OllyDbg などで動作するプラグインで各種アンチデバッギングに自動で対応してくれる優れものです。
OllyDbg に移ってこれを使ってみたところ一通りアンチデバッギングを回避はできているようなんですが、なぜか途中で変なところにジャンプしてしまい、ここで結構悩みました。
ふと、最初のIsDebuggerPresentのところにブレークポイントを置きステップ実行していったところ、途中で無条件に CALL し飛んでいったっきり帰ってこないようになっていることに気づきました。
つまり、0x00401590CALL命令が諸悪の根源であるということに気づき、なのでとりあえずその命令をNOP命令に置き換えてみたところ、少し下の別のところで引っかかるので、JMPで怪しい文字列の直前である0x00401663にジャンプするように置き換え直して、メッセージダイアログが表示されフラグを取ることができました。

00401590   CALL bin.00401240    ; を
00401590 JMP bin.00401663 ; に変更

OllyDbg なら該当の命令を右クリック→AssembleJMP 00401663と入力→Assembleとすればできます。

感想

とりあえず多くの人が解けている問題を全部解けたので満足です。
cheer msgとか200点の問題を解けるともうちょっと楽しめそうなのでいろいろやろうと思います。