CRUD Lab. Tech Blog

ギークス株式会社の沖縄開発拠点CRUDLab. (クラッドラボ)のIT技術(テック)ブログ。kintoneやAngularJSによる開発を行っています。

【kintone】kintoneでステップシーケンサーを作ってみた - 続編

0. 目次

1. 概要

ギークス株式会社CRUD Lab.の、ATSUSHIです。 先日投稿した「(kintoneでステップシーケンサーを作ってみた)http://crud-lab.geechs.com/entry/2016/03/15/090000」の続編です。

kintoneのUIを変更してより楽器らしくしていこうと思います。 ステップシーケンサーって何?という方は前回の記事に簡単に説明と参考リンクを掲載しているので見てみてください。

f:id:crud_lab_editor:20160317165223g:plain

1-1 前回のスペック

  • loop機能なし
  • 音源はピアノ、1オクターブのみ
  • BPM変更可能

1-2 追加機能

  • ステップ上でサウンド再生しない(OFF)機能の追加
  • オクターブを変更できる機能
  • ステップを自由に追加できる機能

1-3 今回フィーチャーするkintoneの技術

2. 実装

2-1 作業の進め方

kintoneでは、作成済みのアプリを再利用することができます。 似たような性質のアプリであれば、効率よく作業をすすめられる便利な機能です。

アプリを新規作成する際に「ほかのアプリを再利用」を選択することで利用可能です。 アプリ名を 「Sequencer Advance」として保存します。

2-2 アプリの設定

複製されたアプリのフィールドコードの編集を以下のポイントで行います。

  • 8つある音階選択のラジオボタンを削除
  • 横レイアウトで音階選択のラジオボタンを1個、新規追加
  • オクターブのラジオボタンを1個、新規追加
  • 上記のパーツをテーブル化

f:id:crud_lab_editor:20160317174159j:plain

... 前回は8ステップ固定でしたが、 テーブル化することで、長さをいくらでも伸ばすことができるようになります。 ループ機能を入れるともっとシーケンサーらしさが出るのですが、前回とのロジック変更が多くなるので、対応しません(苦)

フィールド名 フィールドコード 初期値 フィールドコードタイプ/その他 変更
タイトル title -- -- 流用
BPM bpm 120 -- 流用
- play_button -- 変更なし JavaScritpで buttonタグを挿入するためのスペース 流用
- samples -- 変更なし。JavaScriptで audioタグを挿入するためのスペース 流用
note note OFF ラジオボタン(横) / 1オクターブ、OFFの情報を保持 > テーブル化 新規*
oct oct 0 -1, 0, +1 > テーブル化 新規*

noteoct のフィールドをテーブル化して、レコードを複製できるようにします。 今回は、テーブルの上から下に向かって音声が再生されます。

2-3 JavaScriptのコーディング

アプリ設定「詳細設定」タブを開き、「JavaScript / CSSでカスタマイズ」>「スマートフォン用のJavaScriptファイル」に以下のファイルをリンクするようにしてください。

'use strict';

// 必要なjsライブラリをインクルード
document.write("<script type='text/javascript' src='https://ajax.googleapis.com/ajax/libs/jquery/2.1.4/jquery.min.js'></script>");

// レコードの新規作成、編集時に処理を実行する
kintone.events.on(['app.record.create.show','app.record.edit.show','app.record.detail.show'], function(event){

    // 音階のサウンドファイルをインクルード
    var samples = document.createElement('div');
    samples.id   = "samples";
    kintone.app.record.getSpaceElement("samples").appendChild(samples);
    
    var base_url = "https://kintone-dev-test-xxxx.c9users.io/";
    var audio_tags = '';
    audio_tags += '<audio src="'+base_url+'do.mp3" preload="auto" id="key_C" class="note"></audio>';
    audio_tags += '<audio src="'+base_url+'re.mp3" preload="auto" id="key_D" class="note"></audio>';
    audio_tags += '<audio src="'+base_url+'mi.mp3" preload="auto" id="key_E" class="note"></audio>';
    audio_tags += '<audio src="'+base_url+'fa.mp3" preload="auto" id="key_F" class="note"></audio>';
    audio_tags += '<audio src="'+base_url+'so.mp3" preload="auto" id="key_G" class="note"></audio>';
    audio_tags += '<audio src="'+base_url+'ra.mp3" preload="auto" id="key_A" class="note"></audio>';
    audio_tags += '<audio src="'+base_url+'si.mp3" preload="auto" id="key_B" class="note"></audio>';
    audio_tags += '<audio src="'+base_url+'do.mp3" preload="auto" id="key_C" class="note"></audio>';
    
    audio_tags += '<audio src="'+base_url+'do_minus.mp3" preload="auto" id="key_C_minus" class="note"></audio>';
    audio_tags += '<audio src="'+base_url+'re_minus.mp3" preload="auto" id="key_D_minus" class="note"></audio>';
    audio_tags += '<audio src="'+base_url+'mi_minus.mp3" preload="auto" id="key_E_minus" class="note"></audio>';
    audio_tags += '<audio src="'+base_url+'fa_minus.mp3" preload="auto" id="key_F_minus" class="note"></audio>';
    audio_tags += '<audio src="'+base_url+'so_minus.mp3" preload="auto" id="key_G_minus" class="note"></audio>';
    audio_tags += '<audio src="'+base_url+'ra_minus.mp3" preload="auto" id="key_A_minus" class="note"></audio>';
    audio_tags += '<audio src="'+base_url+'si_minus.mp3" preload="auto" id="key_B_minus" class="note"></audio>';
    audio_tags += '<audio src="'+base_url+'do_minus.mp3" preload="auto" id="key_C_minus" class="note"></audio>';
    
    audio_tags += '<audio src="'+base_url+'do_plus.mp3" preload="auto" id="key_C_plus" class="note"></audio>';
    audio_tags += '<audio src="'+base_url+'re_plus.mp3" preload="auto" id="key_D_plus" class="note"></audio>';
    audio_tags += '<audio src="'+base_url+'mi_plus.mp3" preload="auto" id="key_E_plus" class="note"></audio>';
    audio_tags += '<audio src="'+base_url+'fa_plus.mp3" preload="auto" id="key_F_plus" class="note"></audio>';
    audio_tags += '<audio src="'+base_url+'so_plus.mp3" preload="auto" id="key_G_plus" class="note"></audio>';
    audio_tags += '<audio src="'+base_url+'ra_plus.mp3" preload="auto" id="key_A_plus" class="note"></audio>';
    audio_tags += '<audio src="'+base_url+'si_plus.mp3" preload="auto" id="key_B_plus" class="note"></audio>';
    audio_tags += '<audio src="'+base_url+'do_plus.mp3" preload="auto" id="key_C_plus" class="note"></audio>';
    
    $(audio_tags).appendTo('#samples');
    $('#samples').css({visiblity:'hidden'});
    
    // ボタン
    var play_button      = document.createElement('div'), 
        button_tags      = '<button id="play_button">再生</button>';

    play_button.id   = "play_button";
    kintone.app.record.getSpaceElement("play_button").appendChild(play_button);
    
    $(button_tags).appendTo('#play_button');
    $('#play_button').css({margin:'16px'});

    $('#play_button').on('click',function() {
        
        var record = kintone.app.record.get().record;
        var bpm    = parseInt(record["bpm"].value,10), tempo_ms = (60/bpm)*1000;
        var steps  = record.Table.value, notes=[], octaves=[];
        
        $.each(steps,function(idx, step){
           notes.push(step.value.note.value);
           octaves.push(step.value.oct.value);
        });
        
        
        var interval_id = setInterval(function(){
    
            var id_name = 'key_', note = notes[0], octave = octaves[0];
            
            if(note != 'OFF'){
                id_name += note;
                if(octave == -1) id_name += '_minus';
                if(octave == +1) id_name += '_plus';
                
                var sound_obj = document.getElementById(id_name);
                sound_obj.currentTime=0;
                sound_obj.play();
            }
            notes.shift();
            octaves.shift();
            
        },tempo_ms);
        
        setTimeout(function () {
            clearInterval(interval_id);
            console.log('loop will stop after ' + (tempo_ms) + ' msec!');
        }, tempo_ms*steps.length);
    
    });
});
    
    

2-4 補足説明

テーブルの件数をカウントを元にステップの再生回数を指定しています。 JavaScriptでテーブルのデータを操作する場合は、objectの階層が深いので、適宜変数に入れるなどして 情報を整理しながら、コーディングすることをお勧めします。

オクターブ音の再現は、1オクターブ上/下のサンプルをmp3で作成して読み込んでいますが、 (Web Audio API)https://www.w3.org/TR/webaudio/ を活用すると音源をピッチシフトさせるなどして再生できるのかと思います。(勉強中です)

3. まとめ

kintone x 音楽 はシリーズ化したいところですが、ステップシーケンサーの回は終わりにします。 kintoneから広がるファストシステムの可能性をもっと探っていきたいと思います。