Skip to content

Instantly share code, notes, and snippets.

@canonno
Created July 28, 2020 14:22
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save canonno/2209c7d68870b99d256cb4bac110b37d to your computer and use it in GitHub Desktop.
Save canonno/2209c7d68870b99d256cb4bac110b37d to your computer and use it in GitHub Desktop.
{"name_to_int":
{"ドn-3":1,"ドs-3":2,"レn-3":3,"レs-3":4,"ミn-3":5,"フn-3":6,"フs-3":7,"ソn-3":8,"ソs-3":9,"ラn-3":10,"ラs-3":11,"シn-3":12,
"ドn-2":13,"ドs-2":14,"レn-2":15,"レs-2":16,"ミn-2":17,"フn-2":18,"フs-2":19,"ソn-2":20,"ソs-2":21,"ラn-2":22,"ラs-2":23,"シn-2":24,
"ドn-1":25,"ドs-1":26,"レn-1":27,"レs-1":28,"ミn-1":29,"フn-1":30,"フs-1":31,"ソn-1":32,"ソs-1":33,"ラn-1":34,"ラs-1":35,"シn-1":36,
"ドn0":37,"ドs0":38,"レn0":39,"レs0":40,"ミn0":41,"フn0":42,"フs0":43,"ソn0":44,"ソs0":45,"ラn0":46,"ラs0":47,"シn0":48,
"ドn1":49,"ドs1":50,"レn1":51,"レs1":52,"ミn1":53,"フn1":54,"フs1":55,"ソn1":56,"ソs1":57,"ラn1":58,"ラs1":59,"シn1":60,
"ドn2":61,"ドs2":62,"レn2":63,"レs2":64,"ミn2":65,"フn2":66,"フs2":67,"ソn2":68,"ソs2":69,"ラn2":70,"ラs2":71,"シn2":72,
"ドn3":73,"ドs3":74,"レn3":75,"レs3":76,"ミn3":77,"フn3":78,"フs3":79,"ソn3":80,"ソs3":81,"ラn3":82,"ラs3":83,"シn3":84,
"ーs0":100,"ーn0":100,"レf-3":2,"ミf-3":4,"ソf-3":7,"ラf-3":9,"シf-3":11,"レf-2":14,"ミf-2":16,"ソf-2":19,"ラf-2":21,"シf-2":23,
"レf-1":26,"ミf-1":28,"ソf-1":31,"ラf-1":33,"シf-1":35,"レf0":38,"ミf0":40,"ソf0":43,"ラf0":45,"シf0":47,
"レf1":50,"ミf1":52,"ソf1":55,"ラf1":57,"シf1":59,"レf2":62,"ミf2":64,"ソf2":67,"ラf2":69,"シf2":71,
"レf3":74,"ミf3":76,"ソf3":79,"ラf3":81,"シf3":83},
"int_to_hertz":
{"1":32.703,"2":34.648,"3":36.708,"4":38.891,"5":41.203,"6":43.654,"7":46.249,"8":48.999,"9":51.913,"10":55,"11":58.27,"12":61.735,
"13":65.406,"14":69.296,"15":73.416,"16":77.782,"17":82.407,"18":87.307,"19":92.499,"20":97.999,"21":103.826,"22":110,"23":116.541,
"24":123.471,"25":130.813,"26":138.591,"27":146.832,"28":155.563,"29":164.814,"30":174.614,"31":184.997,"32":195.998,"33":207.652,
"34":220,"35":233.082,"36":246.942,"37":261.626,"38":277.183,"39":293.665,"40":311.127,"41":329.628,"42":349.228,"43":369.994,
"44":391.995,"45":415.305,"46":440,"47":466.164,"48":493.883,"49":523.251,"50":554.365,"51":587.33,"52":622.254,"53":659.255,
"54":698.456,"55":739.989,"56":783.991,"57":830.609,"58":880,"59":932.328,"60":987.767,"61":1046.502,"62":1108.731,"63":1174.659,
"64":1244.508,"65":1318.51,"66":1396.913,"67":1479.978,"68":1567.982,"69":1661.219,"70":1760,"71":1864.655,"72":1975.533,
"73":2093.005,"74":2217.461,"75":2349.318,"76":2489.016,"77":2637.02,"78":2793.826,"79":2959.955,"80":3135.963,"81":3322.438,
"82":3520,"83":3729.31,"84":3951.066,"100":0}
}
////////////////////////////////////////////////
////////////////各種メソッド////////////////////
///////////////////////////////////////////////
//lineからのテキストには、ただの「ド」から「ドs1」まで一音につき1文字から3文字まで表記がある
//それらを「ド」なら「ドn4」といった、半音・全音やオクターブ情報を付与した3文字コードに置き換える
function score_to_name(line_text){
//ファが2文字なので一文字に置き換え、最後にeeを付与し、最後であることを明示する
score = line_text.replace(/ファ/g,"フ") +"ee"
node_list = []
//左から一文字ずつ読んでいく
for (i = 0; i < score.length-2;i++){
node = score.slice(i,i+3);
//ドレミで始まっているか
type1 = /^[ドレミファソラシー]/g
//ドレミの次はsか数字か
type2 = /^[ドレミファソラシー][fs\d]/g
//ドレミの次にsがつくか
type3 = /^[ドレミファソラシー][fs]/g
//ドレミの後にsと数字の両方がつくか
type4 = /^[ドレミファソラシー][fs]\d/g
if (type1.test(node)){
if(type2.test(node)){
if(type3.test(node)){
if(type4.test(node)){
//ドs1みたいな表記>>そのまま格納
node_list.push(node);
}else{
//ドsみたいな表記>>オクターブ情報を付与
node_list.push(node[0]+node[1]+"0");
}
}else{
//ド1みたいな表記>>ナチュラルであるnを付与
node_list.push(node[0]+"n"+node[1]);
}
}else{
//ドみたいな表記>>ナチュラルnとオクターブ情報を付与
node_list.push(node[0]+"n"+"0");
}
}else{
//音階から始まってない>>無視して次の文字へ
;
}
}
return node_list
}
//上記で3文字コードになったものを、数値に置き換える
//一番低い音から1、2、3、と半音ごとに1ずつ上がる数字に置き換える
function node_to_int(node_list){
//3文字コードと数字の対応表をインポート
const dict = JSON.parse(fs.readFileSync('node_dict.txt', 'utf8'));
name2int_dict = dict["name_to_int"]
//ひたすら数値化
int_list = []
for (i=0;i<node_list.length;i++){
int_list.push(name2int_dict[node_list[i]]);
}
return int_list;
}
//上記で数値情報になったものを周波数と音の長さに置き換える
//key情報を引数に入れ、keyの数値分音をずらす処理も行う
function int_to_fre(int_list,key){
//数値と周波数との対応表のインポート
const dict = JSON.parse(fs.readFileSync('node_dict.txt', 'utf8'));
int2fre_dict = dict["int_to_hertz"]
//ひたすら置き換える
fre_list = []
for (i=0;i<int_list.length;i++){
//「ー」の場合(数値を100としている)、ひとつ前の音のlengthを1伸ばす
if (int_list[i]==100){
last_length = fre_list[fre_list.length-1]["length"]
fre_list[fre_list.length-1]["length"] = last_length + 1
//普通の音の場合そのまま変換
}else{
fre_list.push({"frequency":int2fre_dict[int_list[i]+key],"length":1});
}
}
return fre_list;
}
//obnizで出力
function sound_with_obniz(line_text){
//もろもろ初期設定
const Obniz = require('obniz');
const { text } = require("express");
const obniz = new Obniz('Obniz_ID'); // Obniz_IDに自分のIDを入れます
//obnizと接続
obniz.onconnect = async function () {
const speaker = obniz.wired('Speaker', {signal:0, gnd:1});
//obniz上での設定パラメータ
key = 0;
BPM = 180;
mode_list = ['play','key','BPM']
mode_idx = 300
mode = mode_list[mode_idx%3]
// ディスプレイ処理
obniz.display.clear(); // 一旦クリアする
obniz.display.print(mode + "\nkey:"+ key+" BPM:"+BPM);
// スイッチの反応を常時監視
obniz.switch.onchange = async function(state) {
//表示がplayの時の操作
if (mode == 'play'){
//押したら音が鳴る
if (state === 'push') {
one_tempo = Math.round(60/2/BPM*1000);
node_list = score_to_name(line_text);
int_list = node_to_int(node_list);
fre_list = int_to_fre(int_list,key)
for (i=0;i<fre_list.length;i++){
sound(fre_list[i]["frequency"],fre_list[i]["length"]);
}
obniz.display.clear();
obniz.display.print(mode + "\nkey:"+ key+" BPM:"+BPM);
//離せば何も起こらない
} else if (state === 'none') {
speaker.stop();
//右にすればモードが変わる
} else if (state === 'right'){
mode_idx += 1;
mode = mode_list[mode_idx%3]
obniz.display.clear()
obniz.display.print(mode + "\nkey:"+ key+" BPM:"+BPM);
//左にすればモードが変わる
} else if (state === "left"){
mode_idx -= 1;
mode = mode_list[mode_idx%3]
obniz.display.clear()
obniz.display.print(mode + "\nkey:"+ key+" BPM:"+BPM);
}
//表示がkeyの時の操作
} else if (mode == 'key'){
//押したらkeyの変更画面へ
if (state === 'push') {
mode = 'key_select'
obniz.display.clear();
obniz.display.print(mode+"\nkey:"+key);
//離せば何も起こらない
} else if (state === 'none') {
speaker.stop();
//右に倒せばモードが変わる
} else if (state === 'right'){
mode_idx += 1;
mode = mode_list[mode_idx%3];
obniz.display.clear();
obniz.display.print(mode + "\nkey:"+ key+" BPM:"+BPM);
//左に倒してもモードが変わる
} else if (state === "left"){
mode_idx -= 1;
mode = mode_list[mode_idx%3];
obniz.display.clear();
obniz.display.print(mode + "\nkey:"+ key+" BPM:"+BPM);
}
//表示がBPMの時の操作
} else if (mode == 'BPM'){
//押せばBPMの設定画面になる
if (state === 'push') {
mode = 'BPM_select'
obniz.display.clear()
obniz.display.print(mode+"\nBPM:"+BPM)
//離せば何も起こらない
} else if (state === 'none') {
speaker.stop();
//右に倒せばモードが変わる
} else if (state === 'right'){
mode_idx += 1;
mode = mode_list[mode_idx%3]
obniz.display.clear()
obniz.display.print(mode + "\nkey:"+ key+" BPM:"+BPM);
//左に倒してもモードが変わる
} else if (state === "left"){
mode_idx -= 1;
mode = mode_list[mode_idx%3]
obniz.display.clear()
obniz.display.print(mode + "\nkey:"+ key+" BPM:"+BPM);
}
//キーセレクト画面での操作
}else if (mode == 'key_select'){
//押せば元の画面に戻る
if (state === 'push') {
mode = mode_list[mode_idx%3]
obniz.display.clear()
obniz.display.print(mode + "\nkey:"+ key+" BPM:"+BPM);
//離せば何も起こらない
} else if (state === 'none') {
speaker.stop();
//右に倒せばキーが上がる
} else if (state === 'right'){
key += 1;
obniz.display.clear()
obniz.display.print(mode+"\nkey:"+key)
//左に倒せばキーが下がる
} else if (state === "left"){
key -= 1;
obniz.display.clear()
obniz.display.print(mode+"\nkey:"+key)
}
//BPM設定画面での操作
} else if (mode == 'BPM_select'){
//押せば元の画面に戻る
if (state === 'push') {
mode = mode_list[mode_idx%3]
obniz.display.clear()
obniz.display.print(mode + "\nkey:"+ key+" BPM:"+BPM);
//離せば何も起こらない
}else if (state === 'none') {
speaker.stop();
//右に倒せばBPMが上がる
} else if (state === 'right'){
BPM += 20;
obniz.display.clear()
obniz.display.print(mode+"\nBPM:"+BPM)
//左に倒せばBPMが下がる
} else if (state === "left"){
BPM -= 20;
obniz.display.clear()
obniz.display.print(mode+"\nBPM:"+BPM)
}
}
}
//一つ一つの音を出力する処理
function sound(fre,length){
speaker.play(fre); // C5 ド
obniz.wait(length*one_tempo);
speaker.stop();
obniz.wait(100);
}
}
}
///////////////////////////////////////////////
/////////////ここから実行///////////////////////
///////////////////////////////////////////////
'use strict';
const fs = require("fs");
const express = require('express');
const line = require('@line/bot-sdk');
const { compileFunction } = require('vm');
const PORT = process.env.PORT || 3000;
const config = {
channelSecret: 'チャンネルシークレットID',
channelAccessToken: 'チャンネルアクセストークンをここに'
};
const app = express();
//lineからくるテキスト初期値
var line_text = "";
//リクエストによる処理
app.get('/', (req, res) => res.send('Hello LINE BOT!(GET)')); //ブラウザ確認用
app.post('/webhook', line.middleware(config), (req, res) => {
events = req.body.events
line_text = events[0].message.text
Promise
.all(req.body.events.map(handleEvent))
.then((result) => res.json(result));
});
const client = new line.Client(config);
async function handleEvent(event) {
//テキストでない場合は無視
if (event.type !== 'message' || event.message.type !== 'text') {
return Promise.resolve(null);
}
//lineテキストをobnizへ流し込む
sound_with_obniz(line_text)
//lineへの返信
return client.replyMessage(event.replyToken, {
type: 'text',
text: 'obnizでの操作をお楽しみください' //実際に返信の言葉を入れる箇所
});
}
app.listen(PORT);
console.log(`Server running at ${PORT}`);
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment