1 - Getting Started

Let’s start your mimium experiences

実行環境

mimiumは現在以下の環境で利用可能です。

  • macOS(x86のみ)
  • Linux(ALSAを利用します)
  • Windows 10

Visual Studio Code拡張ではじめる

もっとも簡単にmimiumを利用する方法は無料のテキストエディタ/IDEであるVisual Studio Codeを利用する方法です。

  1. Visual Studio Code を公式Webサイトからインストールする。
  2. Visual Studio Codeを起動したら、拡張機能メニューを開く。 (Cmd+Shift+X).
  3. 検索欄から"mimium"と検索し、出てきた拡張をインストールする。
  4. `hello.mmm’という名前でファイルを作成し、以下のコードを貼り付けて保存し、再度開く。
  5. 最新版のmimiumバイナリをダウンロード、インストールするか聞くダイアログが現れるのでインストールする。
  6. Cmd+Shift+P でコマンドパレットを開き、“mimium"で検索する。 “Run currently opening file” を選択すると、ターミナルが新たに立ち上がり、現在開いているファイルを実行してくれる。
  7. 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のページからより詳しい文法の解説に進みましょう。


  1. macOS 11.0ではHomebrewでのバイナリ配布が現在行えないため、ソースからビルドが行われます。この場合XCodeのインストールなどが必要になります。 ↩︎

1.1 - インストール

mimiumをインストールしてみよう

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環境を利用してビルドできます。

加えて、以下のツールやライブラリが必要になります。

macOSでは、xcode-selectでclangをインストールしたタイミングでcmakeとgitはインストールされています。

これらに加えて RtAudio(クロスプラットフォーム向けオーディオドライバライブラリ) にも依存しますが、RtAudioはcmakeが自動でダウンロード&ビルドするので手動でインストールする必要はありません。

これらのツールやライブラリを brew やLinuxの場合は apt-get、MSYS2ではpacmanを用いてインストールするのが簡単です。

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 - サウンドを作る

ここではmimiumを使った基本的なサウンドの作り方を学びます。

440Hzのサイン波の音をつくろう

  1. 初めに「hello.mmm」というファイルを用意します。
  2. そのファイルに以下のスニペットを貼り付けて、ファイルを保存します。
fn dsp(){
    output = sin(now*440*3.14*2/48000)
    return (output,output)
}
  1. 最後にbashなどを使って、先程のプログラムを起動します。
$ mimium hello.mmm

1.3 - サンプル例

mimium初心者のための例を交えた簡単な機能紹介。
  1. dsp系
  2. selfを使用した例
  3. シンプルなエフェクト
  4. composition系
  5. ドレミ音
  6. リズムパターン

サンプル: ドレミ音

下の例では、システムのオーディオドライバーのサンプルレートが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行目では、now48000+演算子で結ぶことで、現時点から先のサンプル時点を定めることができ、さらに@を使うことでそのサンプル時点で関数を実行することができます。

チェックポイント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オクターブ上がった音階を表現することができます。


  1. mimiumには現在オーディオドライバのサンプルレートを動的に取得する方法がありません。これは今後のバージョンで環境変数という形で導入される予定です。。 ↩︎

2 - 言語仕様

言語仕様について解説します

2.1 - 文法定義

mimium言語の文法定義に関する項目です。

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におけるプリミティブ型はfloatstringvoidのみです。

mimiumでは数値型はfloat(内部的には64bit float)のみとなっています。 整数を利用するにはroundceilfloor関数などを利用します。

string型の値は"hoge"のようにダブルクオーテーションで囲った文字列リテラルから生成できます。 現在は文字列の切り出しや結合には対応しておらず、用途は基本的には

  1. printstr関数に渡してデバッグ用途に使う
  2. loadwav関数に渡してオーディオファイルを読み込む
  3. 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

タプルは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)

関数

関数は、複数の値を取って新しい値を返すような、再利用可能な手続きをまとめたものです。

例として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という構文を持っています。 conditionthen_expressionelse_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


  1. mimiumでは+*などの算術演算子を数値型にしか使えないため。今後変更になる可能性もあります。 ↩︎

2.2 - 組み込み関数

mimiumでライブラリなしで利用できるプリミティブな関数

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へのエイリアス

デバッグ用途などに利用される関数です。 標準出力に値を出力します。 printprintlnは数値型のみを受け付けます。printlnは改行を入れて出力します。 printstr("hoge")のようにすると文字列の出力が可能です

loadwav(path:string)->[float x 0] / loadwavsize(path:string)->float

LibSndFileを利用してオーディオファイルを読み込みます。 どちらもオーディオファイル(.wav、.aiff、.flacなど)のファイルパスをパラメータにとります。 パスは絶対パスでなければソースファイルの位置を基準とした相対パスとして解釈されます。

loadwavsize(path)はオーディオファイルのサンプル数を返却します。

loadwav(path)はオーディオファイルを読み込み配列として返却します。 ファイルサイズより大きいインデックスでアクセスした場合はクラッシュしますので、loadwavsizeの値を利用して値を制限して使用する必要があります。