カラオケのキー合わせをする

カラオケでキーが高い曲を歌いたいとき、どのくらいキーを下げればいいのか分からないことが多々あるので、キー調節用のプログラムをPythonで書いてみました。
[追記] [laravelに乗っけてみました](http://qiita.com/banaba0207/items/833300f84fa625d3dc3c)

#解決したい問題
- キーが高くて歌えない曲を自分の最高音に合わせるにはどのくらいキーを下げればいいのか
    - 例：地声の最高音が mid2G#(BUMP OF CHICKEN「天体観測」の最高音)の人が B'zの「ultra soul」(最高音hiC#)を歌うにはどの程度キーを下げればいいのか
    - ちなみに曲の音域情報は[音域.com](http://www.music-key.com/)を参考にしています

#ソース
- ぶっちゃけ、単純に歌いたい曲と自分の最高音との音程差を出してるだけです^^;
- 入力のエラー処理やら使い方の表示やらで、ムダに長いブサイクコード感は否めません
- 追記＜2016/4/18＞
    - 2オクターブまで対応しました
    - キーの種類を増やしました

```py3.karaoke.py
#coding:utf-8
import sys

oniki = [
        'lowF', 'lowF_s', 'lowG', 'lowG_s',
        'mid1A', 'mid1A_s', 'mid1B', 'mid1C', 'mid1C_s', 'mid1D', 'mid1D_s', 'mid1E', 'mid1F', 'mid1F_s', 'mid1G', 'mid1G_s',
        'mid2A', 'mid2A_s', 'mid2B', 'mid2C', 'mid2C_s', 'mid2D', 'mid2D_s', 'mid2E', 'mid2F', 'mid2F_s', 'mid2G', 'mid2G_s',
        'hiA', 'hiA_s', 'hiB', 'hiC', 'hiC_s', 'hiD', 'hiD_s', 'hiE', 'hiF', 'hiF_s', 'hiG', 'hiG_s',
        'hihiA', 'hihiA_s', 'hihiB', 'hihiC', 'hihiC_s', 'hihiD', 'hihiD_s', 'hihiF', 'hihiF_s']

def printAdjustKey(adjust_type, diff_key):
    if   adjust_type == '1OctaveDown': ad_oc = 12
    elif adjust_type == '2OctaveDown': ad_oc = 24
    elif adjust_type == '1OctaveUp'  : ad_oc = -12
    elif adjust_type == '2OctaveUp'  : ad_oc = -24
    else: ad_oc = 0

    print(adjust_type + '\t:\t', diff_key + ad_oc, end='\t')
    if abs(diff_key + ad_oc) > 7: print('x')
    else: print('o')

def Usage():
    print('Usage: python3 karaoke.py [your key] [key your want to sing]')
    print('ex   : python3 karaoke.py mid2G_s hiC_s')
   
    print('Kind of range:')
    cnt = 1
    for key in oniki:
        print(key, end = ' ')
        cnt += 1
        if cnt % 10 == 0: print('')
    sys.exit()

def validation(argv):
    if len(argv) != 3: Usage()
    your_key = argv[1]
    target_key = argv[2]
    
    dict_oniki = {x:i for i, x in enumerate(oniki)}
    if your_key not in dict_oniki or target_key not in dict_oniki:
        Usage()

    return dict_oniki, your_key, target_key

def main(argv):
    dict_oniki, your_key, target_key = validation(argv)
    print('Key that you can sing    : ', your_key)
    print('Key that you want to sing: ', target_key)
    print('')

    print('To adjust key')
    diff_key_num = dict_oniki[your_key] - dict_oniki[target_key]
    printAdjustKey('Original', diff_key_num)
    printAdjustKey('1OctaveDown', diff_key_num)
    printAdjustKey('1OctaveUp', diff_key_num)
    print('');
    printAdjustKey('2OctaveDown', diff_key_num)
    printAdjustKey('2OctaveUp', diff_key_num)

if __name__ == "__main__":
    main(sys.argv)
```

#使い方
- コマンドラインを使用
- 上のソースをコピーして、適当な名前で保存してください
    - ここでは `karaoke.py`と保存したと仮定します
- 例えば、mid2G#が最高音の人がB'z「ultra soul」（最高音hiC#）に合わせてキー調整をしたい場合
   `python3 karaoke.py mid2G_s hiC_s`をコマンドライン上で実行します
    - `_s`は半音上げ記号の#を意味します
        - #は特殊文字（あまり使いたくない）ので、`_s`で代替しています

実行例　(※英語が下手なのはお見逃しを)

```
% python3 karaoke.py mid2G_s hiC_s                               
Key that you can sing    :  mid2G_s
Key that you want to sing:  hiC_s

To adjust key
Original	:	 -5	o
1OctaveDown	:	 7	o
1OctaveUp	:	 -17	x
```

- 出力の`To adjust key`以下が調節するキーになります
    - この結果であれば、原曲から5個キーを下げれば気持ちよく ウルトラソウッ！\ﾊｧｲ/！ 出来るってことですね
        - 5も下げると逆に歌いにくくなるかもですが...
    - ちなみに、調節キー横のマルバツは ±7に収まっているか否かを表します
        - 調節するキーが小さいほうが、歌いやすいかもです



女性曲：西野カナの「会いたくて　会いたくて」震える曲（最高音:hiE）もいってみましょう

```
% python3 karaoke.py mid2G_s hiE                            
Key that you can sing    :  mid2G_s
Key that you want to sing:  hiE

To adjust key
Original	:	 -8	x
1OctaveDown	:	 4	o
1OctaveUp	:	 -20	x
```
- この結果は、4個キーを上げて、1オクターブ下で歌えばいい感じに歌えることを示します


逆に女性が男の曲を歌いたいときのパターンもいってみます。
女性の場合、最低音を合わせる感じで考えます。
女性の最低音がmid1E(いきものがかり「SAKURA」最低音)として
福山雅治の「家族になろうよ」（最低音:lowG#）を歌うパターンを考えます。

```
% python3 karaoke.py mid1E lowG_s                              
Key that you can sing    :  mid1E
Key that you want to sing:  lowG_s

To adjust key
Original	:	 8	x
1OctaveDown	:	 20	x
1OctaveUp	:	 -4	o
```

- この結果は4個キーを下げて、1オクターブ上で歌えば、いい感じに家族になれるであろうことを示します

#まとめ
今回CUIで実行できるキー調整プログラムを書いてみました（単純に音程差を計算しているだけですが）。
CUIなのですごく汎用性が限られますが、現在学習中のlaravel等に適用させて、web上で使えるようにすれば汎用性が広がるかな〜と考えてます。自分の音域と曲名を入力にして、音域.comから曲の音域を引っ張ってくるとかすれば面白そうです。
なにかプログラムミスや「こうした方がエレガントだよ！」等アドバイスがあれば、コメントにてお知らせくださいm(__)m