強火で進め

このブログではプログラム関連の記事を中心に書いてます。

音データをジェネレートする(頑張ればファミコンのピコピコ音も作れるよ)

こちらの記事を参考にしました。

Procedural audio with Unity | Game development | Features by Develop
http://www.develop-online.net/features/1678/Procedural-audio-with-Unity

この記事、バージョン3.5から導入された OnAudioFilterRead を使って音を出すという記事です。 OnAudioFilterRead は本来は鳴らしている音に効果を付けるなど加工する為のメソッドだと思うのですがこれ単体で音を鳴らす為に使っています。

Unity Script Reference – MonoBehaviour.OnAudioFilterRead
http://docs.unity3d.com/Documentation/ScriptReference/MonoBehaviour.OnAudioFilterRead.html

以下のC#のファイルをMain Cameraなどに貼り付けると音を鳴らせます。
【Sinus.cs】

using UnityEngine;
using System;// Needed for Math

public class Sinus : MonoBehaviour
{
	// un-optimized version
	public double frequency = 440;
	public double gain = 0.05;
	private double increment;
	private double phase;
	private double sampling_frequency = 48000;
	private bool playing = false;

	void OnAudioFilterRead (float[] data, int channels)
	{
		if (!playing)
			return;
		// update increment in case frequency has changed
		increment = frequency * 2 * Math.PI / sampling_frequency;
		for (var i = 0; i < data.Length; i = i + channels) {
			phase = phase + increment;
    
			data [i] = (float)(gain * Math.Sin (phase));
			// if we have stereo, we copy the mono data to each channel
			if (channels == 2)
				data [i + 1] = data [i];
			if (phase > 2 * Math.PI)
				phase = 0;
		}
	}
  
	void OnGUI ()
	{
		int y = 10;
		if (GUI.Button (new Rect (10, y, 100, 30), "Play")) {
			playing = true;
		}
		y += 40;
		if (GUI.Button (new Rect (10, y, 100, 30), "Stop")) {
			playing = false;
		}
	}
} 

基本波形

基本波形の正弦波、矩形波三角波、鋸歯波で音を鳴らすサンプルもこちらのサイトを参考に作成しました。

Lazuli » C#での基本波形生成処理の実装(正弦波、矩形波三角波、鋸歯波)
http://nanatomo.com/program/cs/sprogram/265

【PlayWave.cs】

using UnityEngine;
using System;// Needed for Math

public class PlayWave : MonoBehaviour
{
	const double PI = System.Math.PI;
	const double PI2 = PI * 2.0;
	const double PI_2 = PI / 2.0;
	const double sampling_frequency = 48000;
	const double PI2_SR = PI2 / sampling_frequency;
	private enum PlayState {
		Stop,
		SineWave,
		SquareWave,
		TriangleWave,
		SawtoothWave
	}

	const double frequency = 440;
	public double gain = 0.05;
	private double increment;
	private double time;
	private PlayState playState = PlayState.Stop;

	void SineWave(float[] data, int channels) {
		increment = frequency * 2 * PI / sampling_frequency;
		for (var i = 0; i < data.Length; i = i + channels) {
			time = time + increment;
    
			data [i] = (float)(gain * Math.Sin (time));
			if (channels == 2)
				data [i + 1] = data [i];
			if (time > 2 * Math.PI)
				time = 0;
		}
	}

	void SquareWave(float[] data, int channels) {
		increment = frequency * 2 * PI / sampling_frequency;
		for (var i = 0; i < data.Length; i = i + channels) {
			time = time + increment;
    
			data [i] = (float)(gain * ((time % PI2) < PI2 * 0.5 ? 1.0 : -1.0));
			if (channels == 2)
				data [i + 1] = data [i];
			if (time > 2 * Math.PI)
				time = 0;
		}
	}
	
	void TriangleWave(float[] data, int channels) {
		increment = frequency * 2 * PI / sampling_frequency;
		for (var i = 0; i < data.Length; i = i + channels) {
			time = time + increment;
			if (time > 2 * Math.PI)
				time = 0;
    
			double t = (time + PI_2) % PI2;
			data [i] = (float)(gain * ((t < PI ? t - PI : PI - t) / PI_2 + 1.0));
			if (channels == 2)
				data [i + 1] = data [i];
		}
	}
	
	void SawtoothWave(float[] data, int channels) {
		increment = frequency * 2 * PI / sampling_frequency;
		for (var i = 0; i < data.Length; i = i + channels) {
			time = time + increment;
    
			data [i] = (float)(gain * ((time + PI) % PI2) / PI - 1.0);
			if (channels == 2)
				data [i + 1] = data [i];
			if (time > 2 * Math.PI)
				time = 0;
		}
	}
	
	void OnAudioFilterRead (float[] data, int channels)
	{
		switch (playState) {
			case PlayState.SineWave:
				SineWave(data, channels);
				break;
			case PlayState.SquareWave:
				SquareWave(data, channels);
				break;
			case PlayState.TriangleWave:
				TriangleWave(data, channels);
				break;
			case PlayState.SawtoothWave:
				SawtoothWave(data, channels);
				break;
		}
	}
  
	void OnGUI ()
	{
		int y = 10;
		if (GUI.Button (new Rect (10, y, 100, 30), "サイン波")) {
			playState = PlayState.SineWave;
		}
		y += 40;
		if (GUI.Button (new Rect (10, y, 100, 30), "矩形波")) {
			playState = PlayState.SquareWave;
		}
		y += 40;
		if (GUI.Button (new Rect (10, y, 100, 30), "三角波")) {
			playState = PlayState.TriangleWave;
		}
		y += 40;
		if (GUI.Button (new Rect (10, y, 100, 30), "ノコギリ波")) {
			playState = PlayState.SawtoothWave;
		}
		y += 40;
		if (GUI.Button (new Rect (10, y, 100, 30), "Stop")) {
			playState = PlayState.Stop;
		}
	}
} 

関連情報

nakamura001 @ ウィキ - トップページ/Unity(Unity3D)/サウンド/作成
http://www32.atwiki.jp/nakamura001/pages/274.html