Created
August 16, 2016 23:02
-
-
Save ksasao/c99dc644b221eb2752da5a1178b52790 to your computer and use it in GitHub Desktop.
.wavファイルレンダリング
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using System; | |
using System.Collections.Generic; | |
using System.Linq; | |
using System.Text; | |
using System.Threading.Tasks; | |
namespace WavPlayerTest | |
{ | |
public class SortedItems<T> | |
{ | |
private T[] _array; | |
public T this[int index] { get { return _array[index]; } set { _array[index] = value; } } | |
public int Length { get { return _array.Length; } } | |
public SortedItems() | |
{ | |
_array = new T[0]; | |
} | |
/// <summary> | |
/// 値を追加します | |
/// </summary> | |
/// <param name="item">追加する値</param> | |
public void Add(T item) | |
{ | |
if(_array.Length == 0) | |
{ | |
_array = new T[] { item }; | |
return; | |
} | |
T[] tmp = new T[_array.Length + 1]; | |
Array.Copy(_array, tmp, _array.Length); | |
tmp[tmp.Length - 1] = item; | |
Array.Sort(tmp); | |
_array = tmp; | |
} | |
/// <summary> | |
/// 値の配列を追加します | |
/// </summary> | |
/// <param name="items">値の配列</param> | |
public void AddRange(T[] items) | |
{ | |
T[] tmp = new T[_array.Length + items.Length]; | |
Array.Copy(_array, tmp, _array.Length); | |
Array.Copy(items, 0, tmp, _array.Length, items.Length); | |
Array.Sort(tmp); | |
_array = tmp; | |
} | |
/// <summary> | |
/// 指定した値を削除します | |
/// </summary> | |
/// <param name="item">削除対象の値</param> | |
/// <returns>削除したindex(削除対象が見つからない場合は-1)</returns> | |
public int Remove(T item) | |
{ | |
int index = IndexOf(item); | |
if(index >= 0) | |
{ | |
T[] tmp = new T[_array.Length - 1]; | |
Array.Copy(_array, 0, tmp, 0, index); | |
Array.Copy(_array, index + 1, tmp, index, tmp.Length - index); | |
_array = tmp; | |
} | |
return index; | |
} | |
/// <summary> | |
/// 指定した位置の値を削除します | |
/// </summary> | |
/// <param name="index">削除対象のindex</param> | |
/// <returns>削除した値</returns> | |
public T RemoveAt(int index) | |
{ | |
T result = _array[index]; | |
T[] tmp = new T[_array.Length - 1]; | |
Array.Copy(_array, 0, tmp, 0, index); | |
Array.Copy(_array, index + 1, tmp, index, tmp.Length - index); | |
_array = tmp; | |
return result; | |
} | |
/// <summary> | |
/// 値の位置を返します | |
/// </summary> | |
/// <param name="item">値</param> | |
/// <returns>最初に見つかった位置(見つからない場合は負の値)</returns> | |
public int IndexOf(T item) | |
{ | |
return Array.BinarySearch<T>(_array, item); | |
} | |
/// <summary> | |
/// 値を配列に変換します。 | |
/// </summary> | |
/// <returns>ソートされた値の配列</returns> | |
public T[] ToArray() | |
{ | |
// コピーを返す | |
T[] tmp = new T[_array.Length]; | |
Array.Copy(_array, tmp, _array.Length); | |
return tmp; | |
} | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using System; | |
using System.Collections.Generic; | |
using System.ComponentModel; | |
using System.Drawing; | |
using System.Data; | |
using System.Linq; | |
using System.Text; | |
using System.Threading.Tasks; | |
using System.Windows.Forms; | |
using NAudio.Wave; | |
using NAudio.Wave.SampleProviders; | |
using System.Threading; | |
using System.IO; | |
using System.Diagnostics; | |
namespace WavPlayerTest | |
{ | |
public partial class WavPlayer : UserControl | |
{ | |
private string _wavFile = ""; | |
private string _markerFile = ""; | |
private long _position; | |
private SortedItems<float> _marker = new SortedItems<float>(); | |
bool isChanged = false; | |
/// <summary> | |
/// データサンプル数 | |
/// </summary> | |
public long Samples { get; private set; } | |
/// <summary> | |
/// サンプリングレート(Hz) | |
/// </summary> | |
public int SampleRate { get; private set; } | |
public WavPlayer() | |
{ | |
InitializeComponent(); | |
InitializeParams(); | |
} | |
public TimeSpan FromTime { get; private set; } | |
public TimeSpan ToTime { get; private set; } | |
private void InitializeParams() | |
{ | |
_marker.Add(0.0f); | |
_marker.Add(-4.0f); | |
Random rnd = new Random(); | |
for(int i = 0; i < 20; i++) | |
{ | |
_marker.Add((float)rnd.NextDouble()*3); | |
} | |
var data = _marker.RemoveAt(10); | |
} | |
/// <summary> | |
/// 読み取り対象の .wav ファイルを指定します | |
/// </summary> | |
/// <param name="wavFile">.wavファイル名</param> | |
/// <param name="markerFile">時刻を列挙したファイル</param> | |
/// <returns>サンプル数</returns> | |
public long SetFiles(string wavFile, string markerFile) | |
{ | |
_wavFile = wavFile; | |
_markerFile = markerFile; | |
using (WaveFileReader reader = new WaveFileReader(wavFile)) | |
{ | |
CheckFormat(reader); | |
_position = 0; | |
Samples = reader.Length / 2; | |
SampleRate = reader.WaveFormat.SampleRate; | |
hScrollBar1.Maximum = (int)Samples; | |
} | |
if (File.Exists(_markerFile)) | |
{ | |
string[] list = File.ReadAllLines(_markerFile); | |
float[] markers = (from c in list | |
select (float)Convert.ToDouble(c)).ToArray(); | |
_marker.AddRange(markers); | |
} | |
SaveMarkerFile(); | |
isChanged = true; | |
return Samples; | |
} | |
private void SaveMarkerFile() | |
{ | |
string[] data = (from c in _marker.ToArray() | |
select c.ToString("0.0000")).ToArray(); | |
File.WriteAllLines(_markerFile,data); | |
} | |
protected override void OnPaint(PaintEventArgs pe) | |
{ | |
base.OnPaint(pe); | |
DrawMain(pe); | |
} | |
protected override void OnResize(EventArgs e) | |
{ | |
base.OnResize(e); | |
Invalidate(); | |
} | |
protected override void OnMouseMove(MouseEventArgs e) | |
{ | |
base.OnMouseMove(e); | |
} | |
protected override void OnMouseClick(MouseEventArgs e) | |
{ | |
base.OnMouseClick(e); | |
Invalidate(); | |
} | |
private void DrawMain(PaintEventArgs pe) | |
{ | |
if (isChanged) | |
{ | |
Graphics g = pe.Graphics; | |
Rectangle rect = pe.ClipRectangle; | |
SolidBrush b = new SolidBrush(this.ForeColor); | |
int width = rect.Width; | |
int height = rect.Height; | |
int scale = 240; | |
int channel = 0; | |
using (WaveFileReader reader = new WaveFileReader(_wavFile)) | |
{ | |
CheckFormat(reader); | |
int align = reader.WaveFormat.BlockAlign; | |
hScrollBar1.Maximum = (int)(reader.Length / scale / align); | |
int x = hScrollBar1.Value * scale; | |
int dataLength = width * align * scale; | |
byte[] data = new byte[dataLength]; | |
int ms = (int)(1000L * x * align / (reader.WaveFormat.SampleRate * reader.WaveFormat.BlockAlign)); | |
int me = (int)(1000L * (x * align + data.Length) / (reader.WaveFormat.SampleRate * reader.WaveFormat.BlockAlign)); | |
FromTime = new TimeSpan(0, 0, 0, 0, ms); | |
ToTime = new TimeSpan(0, 0, 0, 0, me); | |
string time = FromTime.ToString(@"hh\:mm\:ss\.fff"); | |
string time2 = ToTime.ToString(@"hh\:mm\:ss\.fff"); | |
Console.WriteLine(time); | |
Console.WriteLine(time2); | |
Stopwatch watch = new Stopwatch(); | |
watch.Start(); | |
reader.Seek(channel * 2 + x * align, System.IO.SeekOrigin.Begin); | |
reader.Read(data, 0, data.Length); | |
Bitmap bmp = new Bitmap(width, height); | |
using (Graphics gg = Graphics.FromImage(bmp)) | |
{ | |
Pen pen = new Pen(b); | |
int p = 0; | |
float oldY0 = 0; | |
float oldY1 = 0; | |
for (int i = 0; i < width; i++) | |
{ | |
int min = int.MaxValue; | |
int max = int.MinValue; | |
for (int j = 0; j < scale; j++) | |
{ | |
int a = BitConverter.ToInt16(data, p); | |
p += align; | |
if (max < a) { max = a; } | |
if (a < min) { min = a; } | |
} | |
float y0 = height / 2 - (height * min / 65536f); | |
float y1 = height / 2 - (height * max / 65536f); | |
y1 = (y1 - y0 < 1) ? y1 + 0.5f : y1; | |
gg.DrawLine(pen, i, y0, i, y1); | |
if (i > 0) | |
{ | |
if (y1 > oldY0) | |
{ | |
gg.DrawLine(pen, i - 1, oldY0, i, y1); | |
} | |
if (y0 < oldY1) | |
{ | |
gg.DrawLine(pen, i - 1, oldY1, i, y0); | |
} | |
} | |
oldY0 = y0; | |
oldY1 = y1; | |
} | |
pen.Dispose(); | |
} | |
g.DrawImageUnscaled(bmp, rect); | |
bmp.Dispose(); | |
watch.Stop(); | |
Console.WriteLine("{0} ms", watch.ElapsedMilliseconds); | |
} | |
// カーソル位置に応じた描画 | |
System.Drawing.Point sp = System.Windows.Forms.Cursor.Position; | |
System.Drawing.Point cp = this.PointToClient(sp); | |
g.DrawLine(Pens.White, 0, cp.Y, rect.Width-1, cp.Y); | |
g.DrawLine(Pens.White, cp.X, 0, cp.X, rect.Height-1); | |
b.Dispose(); | |
Play(); | |
} | |
} | |
WaveOut player = new WaveOut(); | |
Object lockObject = new object(); | |
public void Play() | |
{ | |
if(_wavFile == "") | |
{ | |
throw new NoNullAllowedException("SetWaveFileメソッドで.wavファイルを設定してください。"); | |
} | |
Task task = new Task(() => | |
{ | |
using (var reader = new WaveFileReader(_wavFile)) | |
{ | |
long from = ((long) (FromTime.TotalSeconds * reader.WaveFormat.SampleRate)) * reader.WaveFormat.BlockAlign; | |
long len = (int)((ToTime.TotalSeconds - FromTime.TotalSeconds) * reader.WaveFormat.SampleRate) * reader.WaveFormat.BlockAlign; | |
byte[] data = new byte[len]; | |
reader.Seek(from, System.IO.SeekOrigin.Begin); | |
reader.Read(data, 0, data.Length); | |
IWaveProvider provider = new RawSourceWaveStream( | |
new MemoryStream(data), reader.WaveFormat); | |
lock (lockObject) | |
{ | |
if (player.PlaybackState != PlaybackState.Playing) | |
{ | |
player.Stop(); | |
} | |
while(player.PlaybackState != PlaybackState.Stopped) | |
{ | |
Thread.Sleep(10); | |
} | |
player.Init(provider); | |
player.Play(); | |
} | |
} | |
}); | |
task.Start(); | |
} | |
private static void CheckFormat(WaveFileReader reader) | |
{ | |
if (reader.WaveFormat.Channels != 1 || reader.WaveFormat.BitsPerSample != 16) | |
{ | |
throw new FormatException("16bitモノラルのデータではありません"); | |
} | |
} | |
private void hScrollBar1_Scroll(object sender, ScrollEventArgs e) | |
{ | |
Invalidate(); | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment