これは、このセクションの複数ページの印刷可能なビューです。 印刷するには、ここをクリックしてください.
ユーザーガイド
1 - Getting Started
実行環境
mimiumは現在以下の環境で利用可能です。
- macOS(x86のみ)
- Linux(ALSAを利用します)
- Windows 10
Visual Studio Code拡張ではじめる
もっとも簡単にmimiumを利用する方法は無料のテキストエディタ/IDEであるVisual Studio Codeを利用する方法です。
- Visual Studio Code を公式Webサイトからインストールする。
- Visual Studio Codeを起動したら、拡張機能メニューを開く。 (Cmd+Shift+X).
- 検索欄から"mimium"と検索し、出てきた拡張をインストールする。
- `hello.mmm’という名前でファイルを作成し、以下のコードを貼り付けて保存し、再度開く。
- 最新版のmimiumバイナリをダウンロード、インストールするか聞くダイアログが現れるのでインストールする。
- Cmd+Shift+P でコマンドパレットを開き、“mimium"で検索する。 “Run currently opening file” を選択すると、ターミナルが新たに立ち上がり、現在開いているファイルを実行してくれる。
- Ctrl+Cを押すこと音を止めることができる。
// hello.mmm
fn dsp(){
output = sin(now*440*2*3.141595/48000)
return (output,output)
}
その他のインストール方法
GitHub Releaseより最新版のバイナリをダウンロードできます。bin/mimium
を適当な場所(macOS/Linuxであれば/usr/local/bin
など)にコピーしてください。
macOS,Linuxユーザーの場合はHomebrew/Linuxbrewを利用してインストールができます。1
brew install mimium-org/mimium/mimium
手動ビルドなどより詳しい情報は インストールページを参照してください。
また、エディタにVisual Studio Codeを利用している場合は拡張機能の検索からmimium-languageをインストールすることでシンタックスハイライトが利用できます。これ以外の環境の場合はRustのシンタックスハイライトを利用すると概ね正しく表示してくれます。
実行
コマンドラインからmimium
を実行することでmimiumを利用できます。正しくインストールされていれば以下のコマンドからヘルプが参照できます。
$mimium --help
現在の実行ディレクトリにhello.mmm
というファイルを作成し、上のコードをコピーして保存してください。
そして、ターミナルから以下のコマンドを実行してみましょう(スピーカーの音量に注意してください)。440Hzのサイン波が聞こえてくるはずです。
$mimium hello.mmm
Making Soundのページからより詳しい文法の解説に進みましょう。
macOS 11.0ではHomebrewでのバイナリ配布が現在行えないため、ソースからビルドが行われます。この場合XCodeのインストールなどが必要になります。 ↩︎
1.1 - インストール
Homebrewを使ったインストール
macOSとLinux向けのパッケージマネージャツール、Homebrewを利用すると、簡単にmimiumをインストールできます。
もしhomebrewをインストールしていない場合は、ターミナルアプリを開いて、以下の行をコピー&ペースト、Enterキーを押して実行してください。(より詳しい方法はhomebrewのドキュメントを参照してください。)
/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install.sh)"
brew
コマンドが使えるようになったら、以下のコマンドをコピー&ペースト、実行するとインストールされます。
brew tap mimium-org/mimium && brew install mimium
以下のコマンドを打ってバージョンが表示されたらインストール完了です!
mimium --version # will return mimium version:x.x.x
手動インストール
mimiumのビルド済みバイナリをGithub Release Pageからダウンロードすることが可能です。
mimium-vx.x.x-Darwin.zip がmacOS用、 mimium-vx.x.x-Linux.zip がLinux用、 mimium-vx.x.x-Windows.zip がWindows用です。
ダウンロードとzip展開が終わったら、bin
フォルダの中にあるmimium
プログラムを/usr/local/mimium
に、lib
フォルダにあるファイルすべてを/usr/local/lib
にコピー/移動/シンボリックリンクを貼るのいずれかを行ってください。GNU/Linuxにおいては/usr/local/lib
はデフォルトで動的リンクのライブラリパスに入っていないので、/usr/local/lib
を/etc/ld.so.conf.d/
配下のファイルに追記し、ldconfig
をroot権限で実行してください。Windowsでは適当な場所にダウンロードしたフォルダを配置して、環境設定からパスを通してください。
ソースからビルドする
mimiumの実行環境はC++で書かれていますので、ビルドにはC++のコンパイラーが必要です。
macOSの場合はxcode-select --install
を実行してインストールされるclang、Linuxの場合はGCC >= 9が推奨されています。(g++ on macやclang++ on Linuxでは標準ライブラリのリンクに競合を起こすことがあります)
Windowsの場合は、MSYS2のMinGW64環境を利用してビルドできます。
加えて、以下のツールやライブラリが必要になります。
- git(バージョン管理システム)
- cmake(クロスプラットフォームビルドツール)
macOSでは、xcode-select
でclangをインストールしたタイミングでcmakeとgitはインストールされています。
- llvm(コンパイラ基盤) >= v11.0.0
- flex(トークナイザ)
- bison(パーサジェネレータ) >= v3.3
- libsndfile(オーディオファイル読み込みライブラリ)
これらに加えて RtAudio(クロスプラットフォーム向けオーディオドライバライブラリ) にも依存しますが、RtAudioはcmakeが自動でダウンロード&ビルドするので手動でインストールする必要はありません。
これらのツールやライブラリを brew
やLinuxの場合は apt-get
、MSYS2ではpacman
を用いてインストールするのが簡単です。
apt
でインストールできるbison
は3.0.4と古いバージョンでこのプロジェクトに対応していません。手動でインストールする必要があります。自動ビルド&テストのためのGithub Actions Workflow には依存パッケージのインストールや後述のビルド手順も含め、手動ビルドの手順が網羅されていますのでチェックしてみてください。GitHubからソースコードをダウンロード
git clone https://github.com/mimium-org/mimium.git
cd mimium
# 'master' が安定版です。'dev'ブランチで開発版のビルドができます。他、v0.1.0などリリースバージョンのtagを用いてバージョンを変更することが可能です。
git checkout master
CMakeのConfigure
cmake -Bbuild . -DCMAKE_BUILD_TYPE=Debug
このステップでCMakeは自動でRtAudioをダウンロード&ビルドします。
cmake
コマンドには、-D
を先頭につけることで以下のようなオプションが渡せます。
-DCMAKE_INSTALL_PREFIX=/your/directory
後述のインストールステップのコピー先(標準では/usr/local)-DCMAKE_BUILD_TYPE=Debug
最適化のレベルの指定。 ‘Debug’, ‘Release’, ‘MinSizeRel’ , ‘RelWithDebinfo’から選べる-DCMAKE_CXX_COMPILER=/path/to/compiler
ビルドに使用するC++コンパイラの指定。-DBUILD_SHARED_LIBS=ON
ONにするとライブラリを動的リンクライブラリとしてビルドします(Linux、Windowsではうまく動かないケースがあります)。-DBUILD_TEST=ON
テストをビルド対象に含めます。-DENABLE_COVERAGE=ON
GCovを利用したカバレッジ計測のためのコンパイラオプションを有効化します。
ビルド
cmake --build build -j
-j
はビルド時にCPUを並列で使用できる最大スレッド数を指定できます。-j8
なら最大8スレッド、番号なしの-j
は可能な限り多くのコア/スレッドを使用します。
インストール
cmake --build build target=install
アンインストール
cmake --build build --target uninstall
このアンインストールステップでは、先ほどのインストールステップで自動生成された build/install_manifest.txt
に書かれている情報を利用してファイルを削除します。もし失敗した場合はこのファイルの中身を確かめるか、もう一度ビルド、インストールを行ったあとアンインストールするを順番に行ってみてください。
バイナリでインストールした場合は/usr/local/bin/mimium
、/usr/local/lib/libmimium*
を削除してください。
ソースからビルドした場合は以下のコマンドでインストールできます。
Visual Studio Code向けシンタックスハイライト
シンタックスハイライトとして、クロスプラットフォームで動作するVisual Studio Code向けの拡張機能を用意しています。
vscode上でのextensionsパネルでmimium-language
と検索するか、以下のリンクよりインストールをしてください。
https://marketplace.visualstudio.com/items?itemName=mimium-org.mimium-language
1.2 - サウンドを作る
440Hzのサイン波の音をつくろう
- 初めに「hello.mmm」というファイルを用意します。
- そのファイルに以下のスニペットを貼り付けて、ファイルを保存します。
fn dsp(){
output = sin(now*440*3.14*2/48000)
return (output,output)
}
- 最後にbashなどを使って、先程のプログラムを起動します。
$ mimium hello.mmm
1.3 - サンプル例
- dsp系
- selfを使用した例
- シンプルなエフェクト
- composition系
- ドレミ音
- リズムパターン
サンプル: ドレミ音
下の例では、システムのオーディオドライバーのサンプルレートが48000Hzの時、ドレミファソラシドを1秒おきに鳴らします。
notes = [260.7,293.3,330,347.7,391.1,440,495]
index = 0
fn updateIndex(){
index = (index+1)%7
updateIndex()@(now+48000)
}
updateIndex()@48000
fn dsp(){
vol = 0.2
octave = 1
sec = now/48000
freq = notes[index]
out = vol * sin(octave*freq*3.14*2*sec)
return (0,out)
}
チェックポイント1「配列」
notes = [260.7,293.3,330,347.7,391.1,440,495] // 1行目
mimiumでは、配列を定義することができます。配列の定義は[]
でおこないます。インデックスの先頭は0です。
この例のドレミ音を作る1行目の配列には、ドレミファソラシ音の周波数を格納し、その後の処理で使用しています。
- ド音: 260.7Hz
- レ音: 293.3Hz
- ミ音: 330Hz
- ファ音: 347.7Hz
- ソ音: 391.1Hz
- ラ音: 440Hz
- シ音: 495Hz
配列の利用の仕方は、1,2行目のように配列名[インデックス]
で表現します。
freq = notes[index] // 1,2行目
チェックポイント2 継時再帰(Temporal Recursion)
// 3~7行目
fn updateIndex(){
index = (index+1)%7
updateIndex()@(now+48000)
}
updateIndex()@48000
v0.3.0現在の仕様では、一般的な言語がもつforループ文は採用していませんが、再帰関数を定義して、再帰ループを3~6行目のように表現することができます。
ドレミ音の例では、7行目で48000サンプル時にupdateIndex()
を実行した後、関数内でnow
キーワードと@
キーワードを併用して、現時点から48000サンプル時点にupdateIndex()
を実行しています(5行目)。
チェックポイント3「nowキーワードと@キーワードの併用」
updateIndex()@(now+48000) // 5行目
mimiumでは、現在のサンプル数をnow
で取得することができます。ユーザーは、v0.3.0現在の仕様では、now
キーワードが、リアルタイム時間を表していないことに注意してください。単位はサンプルです1。
また、mimiumには、@
キーワードという演算子があります。
これは 「@
キーワード以降の式で算出されたサンプル数のときに、@
前の関数を実行する」 という意味になります。
さらに、@
の時間は、オーディオドライバが起動してからの絶対時間を示しており、7行目のようにupdateIndex()@48000
と書いた場合は、必ず起動してから48000サンプル後に1度だけupdateIndex()
を実行する形になります。
例の5行目では、now
と48000
を+
演算子で結ぶことで、現時点から先のサンプル時点を定めることができ、さらに@
を使うことでそのサンプル時点で関数を実行することができます。
チェックポイント4「オクターブ」
// 8~15行目
fn dsp(){
vol = 0.2
octave = 1
sec = now/48000
freq = notes[index]
out = vol * sin(octave*freq*3.14*2*sec)
return (0,out)
}
音階は、振動数(Hz)が倍になれば1オクターブ上がり、反対に半分になれば1オクターブ下がる関係性があります。例の8〜15行目では、octave = 1
と固定なので260.7Hz〜495Hzのドレミファソラシド音を鳴らすのですが、例えばこの値を2と変更すれば1オクターブ上がった音階を表現することができます。
mimiumには現在オーディオドライバのサンプルレートを動的に取得する方法がありません。これは今後のバージョンで環境変数という形で導入される予定です。。 ↩︎
2 - 言語仕様
言語仕様について解説します
2.1 - 文法定義
mimium言語の文法規則に関する項目です。
コメントアウト
C++やJavaScriptと同様、行中の//
より右側はコメントとして扱われます。
また/* */
のように囲むと、複数行をまとめてコメントアウトできます。
変数宣言、代入
mimiumでは=
演算子で値を代入すると、左辺に指定した名前の変数がまだ存在していなければ新しく変数が作られます。
letのような変数宣言時のキーワードは必要ありません。
mynumber = 1000
変数はすべて変更可能(mutable)です。すでに宣言されている変数に新たに値を代入もできます。
mynumber = 1000 // variable is declared, and 1000 is assigned
mynumber = 2000 // 2000 is newly assigned to mynumber
型
型とは変数などのデータを数値や文字列など目的に応じて区別するための概念です。 mimiumは静的型付け言語と呼ばれる、コンパイル時に(音を実際に鳴らす前)すべての型が決定される言語です。
静的型付け言語は一般的に、実行中に型をチェックする言語よりも実行速度の面で有利です。その一方、型の指定を手動で行う場合は記述が長くなりがちというデメリットも存在しますが、mimiumでは型推論と呼ばれる、文脈から型が自動的に決定できる場合は型注釈を省略できる機能が存在しているので、コードを簡潔に保つことが可能です。
型にはそれ以上分解できない最小単位であるプリミティブ型と、複数の型を組み合わせて作る合成型(aggregate type)が存在します。
型の明示的な注釈は変数の宣言と関数の宣言時に可能です。
変数および関数のパラメータでは名前に続けて:
(コロン)を挟み型名を書くことで指定可能です。
myvar:float = 100
以下のように異なる型へ代入した場合はコンパイル時にエラーが発生します。
myvar:string = 100
関数での型宣言では返り値をパラメータの括弧に続けて->
を挟んで書くことで指定できます。
fn add(x:float,y:float)->float{
return x + y
}
このadd関数の場合、文脈からxとyがfloatであることを予測できる1ので以下のように省略できます。
fn add(x,y){
return x+y
}
プリミティブ型
mimiumにおけるプリミティブ型はfloat
とstring
、void
のみです。
mimiumでは数値型はfloat
(内部的には64bit float)のみとなっています。
整数を利用するにはround
、ceil
、floor
関数などを利用します。
string
型の値は"hoge"
のようにダブルクオーテーションで囲った文字列リテラルから生成できます。
現在は文字列の切り出しや結合には対応しておらず、用途は基本的には
printstr
関数に渡してデバッグ用途に使うloadwav
関数に渡してオーディオファイルを読み込むinclude
に渡して他のソースファイルを読み込む
のいずれかに限られています。
void
は値を持たない型で、関数の返り値が存在しないことを明示するのに使用します。
合成型
配列
配列は、同じ型の値を複数個連続して格納できる型です。[]
(アングルブラケット)で囲んだカンマ区切りの値で生成できます。
myarr = [1,2,3,4,5,6,7,8,9,10]
配列型の値にmyarr[0]
のようにアングルブラケットで0基準のインデックスを指定することで配列の値を取り出すことができます。
arr_content = myarr[0] //arr_content should be 1
また左辺値に同様にアングルブラケットを使うことで配列の中身を書き換えることができます。
myarr[4] = 20 //myarr becomes [1,2,3,4,20,6,7,8,9,10]
配列のサイズは固定です。配列の後ろに値を追加していくような操作はできません。また境界チェックもないため範囲外へのアクセスはクラッシュを引き起こします。
自動内挿
インデックスは小数点以下の値でアクセスされた場合、自動で線形補完されて出力されます。
arr_content = myarr[1.5] //should be 2.5
自動で整数に丸められることはないので内挿を避けたい場合はround
関数などでインデックスを丸める必要があります。
タプル
タプルは、異なる型を1つにまとめた値です。変数を()
(丸括弧)で囲んでカンマ区切りの変数を入れることで生成できます。
タプルは配列とも似ていますが、各要素で異なる型を持つことができます。
mytup = (100,200,300)
左辺値にカンマ区切りの変数を置くことでタプルの値を取り出すことができます。この時には括弧で区切る必要がありません。
one,two,three = mytup
mytup.1
のようにインデックスで取り出す記法も実装される予定です。タプルはmimiumの中では典型的に信号処理でステレオやマルチチャンネルなどのオーディオ信号のチャンネルをまとめて扱うために利用されています。
型エイリアス
タプルは型注釈が長いので、以下のような構文でエイリアスを作ることができます。
type FilterCoeffs = (float,float,float,float,float)
構造体(レコード型)
構造体は、タプルと同じ機能を持ちますがフィールド名を持たせることが可能です。
構造体型の変数には変数.フィールド名
のようにドット演算子でアクセスすることができます。
構造体は無名型が作れません。 先に型エイリアスを宣言してから型名{変数1,変数2...}
という構文で初期化して使用する形になります。
type MyBigStruct = {"field1":float,"field2":FilterCoeffs,"field3":string}
mystr = MyBigStruct{100,(0.0,1.0,1.2,0.8,0.4),"test"}
println(mystr.field1)
printlnstr(mystr.field3)
mystr.fst = 111
のように構造体へ再代入する構文は現在実装中です。関数
関数は、複数の値を取って新しい値を返すような、再利用可能な手続きをまとめたものです。
例として2つの値を足算して返すだけのadd関数を考えます。
mimiumで型を明示して変数として格納する場合は以下のように書きます。
fn add(x,y){
return x+y
}
mimiumでは関数が第一級の値として扱えます。これは、関数を変数に代入したり、関数のパラメータとして取ったりすることができるということです。
たとえば、先ほどのadd関数の型注釈は(float,float)->float
のようになっています。先ほどのadd関数を変数に代入する場合は以下のように書けます。関数を関数のパラメータとして代入する場合は高階関数の項を参照してください。
my_function:(float,float)->float = add
無名関数(ラムダ式)
実は先ほどの関数宣言は以下のような、無名関数を変数に格納する構文へのエイリアスです。
add = |x:float,y:float|->float{return x+y}
このような関数を変数に代入しないまま直接呼び出すことも可能です。
println(|x,y|{return x + y}(1,2)) //print "3"
またブロックの構文のところで解説しますが、ブロックの最後の1行はreturnの代わりに単に式を置くことで、returnの代わりにできます。つまり、add
関数は型推論も組み合わせると以下の例まで省略できます。
add = |x,y|{x+y}
パイプ(|>
)演算子
mimiumではパイプ演算子|>
利用することでa(b(c(d)))
のようにネストした関数呼び出しをd |> c |> b |> a
のように書き換えることができます。
再帰によるループ
名前のついている関数は自分自身を呼び出すことも可能です。
階乗を計算するfact関数は以下のように定義できます。
fn fact(input:float){
if(input>0){
return 1
}else{
return input * fact(input-1)
}
}
再帰関数は無限ループを発生させる可能性があるので注意して使用してください。
self
関数の中では、self
という特別なキーワードが使用できます。
self
は関数が最後に返した値を参照できる変数です。たとえば、以下のような関数を作ると呼び出される度increment
ずつ増える値を返します。
fn counter(increment){
return self+increment
}
selfは基本的にdsp
関数を起点にして呼び出される関数でのみ使用できます。selfはオーディオエンジンが開始された時に0で初期化され、呼び出しコンテキストごとに別々の値が生成、管理されます。
たとえば以下の例ではcounter
関数にそれぞれ異なるincrementを与えていますが、この場合内部的にselfのためのメモリは2つ分確保され、lchは毎サンプル0.01ずつ増えて1を越えるたび0にリセットされ、rchは毎サンプル0.05ずつ増えます。
fn dsp()->(float,float){
lch = counter(0.01)%1
rch = counter(0.05)%1
return (lch,rch)
}
変数のスコープ
mimiumはレキシカルスコープと呼ばれる言語で、関数の外側で定義されている変数を参照することが可能です。
TBD
式(expression)、文(statement)、ブロック
関数などで使われていた中括弧{}
で囲まれた文の集まりはブロックと呼ばれる単位です。
文(statement)はほとんどの場合a = b
のような式の代入をする構文で構成されています。
**式(expression)**は1000
のような数字、mynumber
のような変数シンボル、1+2*3
のような演算式、add(x,y)
のような返り値を持つ関数呼び出しなどで構成される単位です。
ブロックは実は式の1つです。
ブロックには複数の文を置くことができ、最後の1行はreturn
を使って返却する値を指定できます。また最後の行のreturnは省略も可能です。
たとえば以下のような構文も文法上は正しいです。(v0.3.0現在この構文は実装が間違っていて動きません。)
//mynumber should be 6
mynumber = {
x = 2
y = 4
return x+y
}
条件分岐
mimiumの条件分岐はif (condition) then_expression else else_expression
という構文を持っています。
condition
、then_expression
、else_expression
はすべて式です。
conditionの値が0より大きい時then_expression
部分が、そうでなければelse_expression
が評価されます。
then/elseの部分をブロックとして表現すれば、以下のようにC言語風の書き方ができます。
fn fact(input:float){
if(input>0){
return 1
}else{
return input * fact(input-1)
}
}
一方でif文自体も式として扱えるので、同じ構文を以下のように書き換えることもできます。 条件部分の括弧は省略することができません。
fn fact(input:float){
return if (input>0) 1 else input * fact(input-1)
}
@
演算子による遅延実行
関数呼び出しに続けて@
と数値型の値を続けることで、関数の実行を遅らせることができます。
時間の単位はサンプルです。
たとえば以下の例ではオーディオドライバをスタートしてから0サンプル目と48000サンプル目に、100と200を続けて標準出力に書き込みます。
println(100)@0
println(200)@48000
現在@
演算子はvoid
型の(返り値を持たない)関数にのみ使用することが可能です。
再帰関数の実行を@
で遅延させることにより、一定間隔で特定の処理を繰り返すことも可能です。
たとえば以下の例では48000サンプル間隔で0から1ずつ数値を増やして標準出力に書き込みます。
fn loopprint(input)->void{
println(input)
loopprint(input+1)@(now+48000)
}
loopprint(0)@0
include
include("path/to/file.mmm")
という構文を用いると他のファイルをそのファイル内で読み込むことができます。
ファイルパスは絶対パスもしくはそのファイルからの相対パスで指定します。 現在は名前空間の分割などはなく、純粋にinclude文をそのファイルのテキストに置換するだけになっています(ただし、一度読み込まれたファイルが2回以上読み込まれることはありません)。
BNFによる文法定義、演算子の優先順位など
TBD
mimiumでは
+
や*
などの算術演算子を数値型にしか使えないため。今後変更になる可能性もあります。 ↩︎
2.2 - 組み込み関数
mimiumにおける組み込み関数について説明します。
delay(input:float,time:float)->float
入力をtime(単位:sample)だけ遅らせた値を返します。
たとえばディレイはselfと組み合わせることで以下のようなフィードバックディレイを作ることが可能です。
fn fbdelay(input:float,time:float,feedback:float){
return delay(input*self*feedback,time)
}
random()->float
-1~1のランダムな値を返します。 C++言語上での実装は以下のようになっています。
(double)rand() / RAND_MAX) * 2 - 1
数学関数
C言語のmath.hの以下の関数を呼び出します。注記がない場合は1つのfloatを受け取り1つのfloatを返却します。
sin
cos
tan
asin
acos
atan
atan2
(x,y)sinh
cosh
tanh
log
log10
exp
pow
(x,y)sqrt
abs
ceil
floor
trunc
round
fmod
(x,y)%
演算子はこの関数へのエイリアスですremainder
(x,y)min
(x,y) fminへのエイリアスmax
(x,y) fmaxへのエイリアス
print / println / printstr
デバッグ用途などに利用される関数です。
標準出力に値を出力します。
print
、println
は数値型のみを受け付けます。println
は改行を入れて出力します。
printstr("hoge")
のようにすると文字列の出力が可能です
loadwav(path:string)->[float x 0] / loadwavsize(path:string)->float
LibSndFileを利用してオーディオファイルを読み込みます。 どちらもオーディオファイル(.wav、.aiff、.flacなど)のファイルパスをパラメータにとります。 パスは絶対パスでなければソースファイルの位置を基準とした相対パスとして解釈されます。
loadwavsize(path)
はオーディオファイルのサンプル数を返却します。
loadwav(path)
はオーディオファイルを読み込み配列として返却します。
ファイルサイズより大きいインデックスでアクセスした場合はクラッシュしますので、loadwavsizeの値を利用して値を制限して使用する必要があります。