Nimでサウンドプログラミング(超入門レベル)


Nim言語で、サウンドプログラミングをします。

初めに

免責

  • 筆者はNimプログラミングもサウンドプログラミングもド素人です

環境

  • nim 1.2.6 (64bit)
  • VC++2019
  • Windows限定

この記事のソースコード・dllが含まれるリポジトリ

「ド」の音を再生する

参考書によると、mmsystem.hというのを読み込んでうまいことコンパイルすれば、Windowsで自由に音が出せるようです。

Nimでは下記のライブラリがmmsystemのラッパーを提供してくれているので利用します(ライブラリ作者の方に感謝

nimble install winimで事前にインストールしておきます。

import math
import winim/inc/mmsystem

const SRATE = 44100
const PI = 3.14159286

proc main() =
  var hWave: HWAVEOUT
  var whdr: WAVEHDR
  var wfe: WAVEFORMATEX
  var b_time = 1.0
  let data_len = int32(SRATE * b_time)
  var bWave: cstring = cast[cstring](alloc0(data_len))
  var f0 = 440.0
  var amplitude = 40.0

  for count in 0..data_len:
    bWave[count] = char(amplitude * sin(2 * PI * f0 * float(count) / SRATE))

  wfe.wFormatTag = WAVE_FORMAT_PCM
  wfe.nChannels = 1
  wfe.nSamplesPerSec = SRATE
  wfe.nAvgBytesPerSec = SRATE
  wfe.wBitsPerSample = 8
  wfe.nBlockAlign = uint16(int(wfe.nChannels) * int(wfe.wBitsPerSample) / 8)

  waveOutOpen(hWave.addr, WAVE_MAPPER, wfe.addr, 0, 0, CALLBACK_NULL)

  whdr.lpData = bWave
  whdr.dwBufferLength = data_len
  whdr.dwFlags = WHDR_BEGINLOOP or WHDR_ENDLOOP
  whdr.dwLoops = 1

  waveOutPrepareHeader(hWave, whdr.addr, int32(sizeof(WAVEHDR)))
  waveOutWrite(hWave, whdr.addr, int32(sizeof(WAVEHDR)))

  echo("終了するには何かキーを押してください:")
  discard readLine(stdin)


when isMainModule:
  main()

これをnim c -rで実行すれば、ドの音が流れてきます(音量に注意)。

MIDIファイルを作成する

参考書はおーぷんMIDIぷろじぇくとが提供しているライブラリを利用しているので、それを何とかNimでも利用できるようにします。

必要なファイル

MIDIData.nimはc2nimで作成しました。MIDIData.hから不要そうなマクロの定義を削除し、api定義のpragmaをいい感じに修正&wchar_tをwinimの定義と合わせる感じで修正を行いました。

MIDIData.dllは配布されているdllが32bitのものだったので、VC++2019で64bitにコンパイルしなおして利用しました。

上記のファイルをダウンロードしたら、ダウンロードした場所に下記のソースコードを作成します。

import winim
import MIDIData

proc main() =
  let midiData: ptr MIDIData = MIDIData_Create(MIDIDATA_FORMAT0, 1, MIDIDATA_TPQNBASE, 120)
  let midiTrack: ptr MIDITrack = MIDIData_GetFirstTrack(midiData)
  MIDITrack_InsertTrackNameW(midiTrack, 0, &T"ドレミ")
  MIDITrack_InsertTempo(midiTrack, 0, clong(60000000 / 120))
  MIDITrack_InsertProgramChange(midiTrack, 0, 0, 1)

  # 音符
  MIDITrack_InsertNote(midiTrack, 0, 0, 60, 100, 120) # ド
  MIDITrack_InsertNote(midiTrack, 120, 0, 62, 100, 120) # レ
  MIDITrack_InsertNote(midiTrack, 240, 0, 64, 100, 120) # ミ

  MIDITrack_InsertEndofTrack(midiTrack, 360)
  MIDIData_SaveAsSMFW(midiData, &T"doremi.midi")
  MIDIData_Delete(midiData)

when isMainModule:
  main()

これをnim c -rで実行すると、doremi.midiファイルが作成されます。Windows Media Playerで再生すれば、ピアノ音のドレミを聴くことができます。