qiangqiang101 Posted April 26, 2016 Share Posted April 26, 2016 C# using System;using System.IO;using System.Media;class WaveStream : Stream { public override bool CanSeek { // シークはサポートしない get { return false; } } public override bool CanRead { get { return !IsClosed; } } public override bool CanWrite { // 書き込みはサポートしない get { return false; } } private bool IsClosed { get { return reader == null; } } public override long Position { get { CheckDisposed(); throw new NotSupportedException(); } set { CheckDisposed(); throw new NotSupportedException(); } } public override long Length { get { CheckDisposed(); throw new NotSupportedException(); } } public int Volume { get { CheckDisposed(); return volume; } set { CheckDisposed(); if (value < 0 || MaxVolume < value) throw new ArgumentOutOfRangeException("Volume", value, string.Format("0から{0}の範囲の値を指定してください", MaxVolume)); volume = value; } } public WaveStream(Stream baseStream) { if (baseStream == null) throw new ArgumentNullException("baseStream"); if (!baseStream.CanRead) throw new ArgumentException("読み込み可能なストリームを指定してください", "baseStream"); this.reader = new BinaryReader(baseStream); ReadHeader(); } public override void Close() { if (reader != null) { reader.Close(); reader = null; } } // dataチャンクまでのヘッダブロックの内容をバッファに読み込んでおく // WAVEFORMAT等のヘッダ内容のチェックは省略 private void ReadHeader() { using (var headerStream = new MemoryStream()) { var writer = new BinaryWriter(headerStream); // RIFFヘッダ var riffHeader = reader.ReadBytes(12); writer.Write(riffHeader); // dataチャンクまでの内容をwriterに書き写す for (; { var chunkHeader = reader.ReadBytes(8); writer.Write(chunkHeader); var fourcc = BitConverter.ToInt32(chunkHeader, 0); var size = BitConverter.ToInt32(chunkHeader, 4); if (fourcc == 0x61746164) // 'data' break; writer.Write(reader.ReadBytes(size)); } writer.Close(); header = headerStream.ToArray(); } } public override int Read(byte[] buffer, int offset, int count) { CheckDisposed(); if (buffer == null) throw new ArgumentNullException("buffer"); if (offset < 0) throw new ArgumentOutOfRangeException("offset", offset, "0以上の値を指定してください"); if (count < 0) throw new ArgumentOutOfRangeException("count", count, "0以上の値を指定してください"); if (buffer.Length - count < offset) throw new ArgumentException("配列の範囲を超えてアクセスしようとしました", "offset"); if (header == null) { // dataチャンクの読み込み // WAVEサンプルを読み込み、音量を適用して返す // ストリームは16ビット(1サンプル2バイト)と仮定 // countバイト以下となるよう読み込むサンプル数を決定する var samplesToRead = count / 2; var bytesToRead = samplesToRead * 2; var len = reader.Read(buffer, offset, bytesToRead); if (len == 0) return 0; // 終端まで読み込んだ // 読み込んだサンプル1つずつにボリュームを適用する for (var sample = 0; sample < samplesToRead; sample++) { short s = (short)(buffer[offset] | (buffer[offset + 1] << 8)); s = (short)(((int)s * volume) / MaxVolume); buffer[offset] = (byte)(s & 0xff); buffer[offset + 1] = (byte)((s >> 8) & 0xff); offset += 2; } return len; } else { // ヘッダブロックの読み込み // バッファに読み込んでおいた内容をそのままコピーする var bytesToRead = Math.Min(header.Length - headerOffset, count); Buffer.BlockCopy(header, headerOffset, buffer, offset, bytesToRead); headerOffset += bytesToRead; if (headerOffset == header.Length) // ヘッダブロックを全て読み込んだ // (不要になったヘッダのバッファを解放し、以降はdataチャンクの読み込みに移る) header = null; return bytesToRead; } } public override void SetLength(long @value) { CheckDisposed(); throw new NotSupportedException(); } public override long Seek(long offset, SeekOrigin origin) { CheckDisposed(); throw new NotSupportedException(); } public override void Flush() { CheckDisposed(); throw new NotSupportedException(); } public override void Write(byte[] buffer, int offset, int count) { CheckDisposed(); throw new NotSupportedException(); } private void CheckDisposed() { if (IsClosed) throw new ObjectDisposedException(GetType().FullName); } private BinaryReader reader; private byte[] header; private int headerOffset = 0; private int volume = MaxVolume; private const int MaxVolume = 100;} VB Imports SystemImports System.IOClass WaveStream Inherits Stream Public Overrides ReadOnly Property CanSeek As Boolean Get ' シークはサポートしない Return False End Get End Property Public Overrides ReadOnly Property CanRead As Boolean Get Return Not IsClosed End Get End Property Public Overrides ReadOnly Property CanWrite As Boolean Get ' 書き込みはサポートしない Return False End Get End Property Private ReadOnly Property IsClosed As Boolean Get Return reader Is Nothing End Get End Property Public Overrides Property Position As Long Get CheckDisposed() Throw New NotSupportedException() End Get Set(ByVal value As Long) CheckDisposed() Throw New NotSupportedException() End Set End Property Public Overrides ReadOnly Property Length As Long Get CheckDisposed() Throw New NotSupportedException() End Get End Property Public Property Volume As Integer Get CheckDisposed() Return _volume End Get Set(ByVal value As Integer) CheckDisposed() If value < 0 OrElse MaxVolume < value Then Throw New ArgumentOutOfRangeException("Volume", value, String.Format("0から{0}の範囲の値を指定してください", MaxVolume)) End If _volume = value End Set End Property Public Sub New(ByVal baseStream As Stream) If baseStream Is Nothing Then Throw New ArgumentNullException("baseStream") If Not baseStream.CanRead Then Throw New ArgumentException("読み込み可能なストリームを指定してください", "baseStream") reader = New BinaryReader(baseStream) ReadHeader() End Sub Public Overrides Sub Close() If Not reader Is Nothing Then reader.Close() reader = Nothing End If End Sub ' dataチャンクまでのヘッダブロックの内容をバッファに読み込んでおく ' WAVEFORMAT等のヘッダ内容のチェックは省略 Private Sub ReadHeader() Using headerStream As New MemoryStream() Dim writer As New BinaryWriter(headerStream) ' RIFFヘッダ Dim riffHeader() As Byte = reader.ReadBytes(12) writer.Write(riffHeader) ' dataチャンクまでの内容をwriterに書き写す Do Dim chunkHeader() As Byte = reader.ReadBytes(8) writer.Write(chunkHeader) Dim fourcc As Integer = BitConverter.ToInt32(chunkHeader, 0) Dim size As Integer = BitConverter.ToInt32(chunkHeader, 4) If fourcc = &H61746164 Then Exit Do 'data' writer.Write(reader.ReadBytes(size)) Loop writer.Close() header = headerStream.ToArray() End Using End Sub Public Overrides Function Read(ByVal buffer() As Byte, ByVal offset As Integer, ByVal count As Integer) As Integer CheckDisposed() If buffer Is Nothing Then Throw New ArgumentNullException("buffer") If offset < 0 Then Throw New ArgumentOutOfRangeException("offset", offset, "0以上の値を指定してください") If count < 0 Then Throw New ArgumentOutOfRangeException("count", count, "0以上の値を指定してください") If buffer.Length - count < offset Then Throw New ArgumentException("配列の範囲を超えてアクセスしようとしました", "offset") If header Is Nothing Then ' dataチャンクの読み込み ' WAVEサンプルを読み込み、音量を適用して返す ' ストリームは16ビット(1サンプル2バイト)と仮定 ' countバイト以下となるよう読み込むサンプル数を決定する Dim samplesToRead As Integer = count \ 2 Dim bytesToRead As Integer = samplesToRead * 2 Dim len As Integer = reader.Read(buffer, offset, bytesToRead) If len = 0 Then Return 0 ' 終端まで読み込んだ ' 読み込んだサンプル1つずつにボリュームを適用する For sample As Integer = 0 To samplesToRead - 1 Dim s As Short = CShort(buffer(offset)) Or (CShort(buffer(offset + 1)) << 8) s = CShort((CInt(s) * _volume) \ MaxVolume) buffer(offset) = CByte(s And &HFF) buffer(offset + 1) = CByte((s >> 8) And &HFF) offset += 2 Next Return len Else ' ヘッダブロックの読み込み ' バッファに読み込んでおいた内容をそのままコピーする Dim bytesToRead As Integer = Math.Min(header.Length - headerOffset, count) System.Buffer.BlockCopy(header, headerOffset, buffer, offset, bytesToRead) headerOffset += bytesToRead If headerOffset = header.Length Then ' ヘッダブロックを全て読み込んだ ' (不要になったヘッダのバッファを解放し、以降はdataチャンクの読み込みに移る) header = Nothing End If Return bytesToRead End If End Function Public Overrides Sub SetLength(ByVal value As Long) CheckDisposed() Throw New NotSupportedException() End Sub Public Overrides Function Seek(ByVal offset As Long, ByVal origin As SeekOrigin) As Long CheckDisposed() Throw New NotSupportedException() End Function Public Overrides Sub Flush() CheckDisposed() Throw New NotSupportedException() End Sub Public Overrides Sub Write(ByVal buffer() As Byte, ByVal offset As Integer, ByVal count As Integer) CheckDisposed() Throw New NotSupportedException() End Sub Private Sub CheckDisposed() If IsClosed Then Throw New ObjectDisposedException(Me.GetType().FullName) End Sub Private reader As BinaryReader Private header() As Byte Private headerOffset As Integer = 0 Private _volume As Integer = MaxVolume Private Const MaxVolume As Integer = 100End Class Usage Public Shared Sub WavePlayer(waveFile As String, Optional volume as Integer = 50) Using stream As New WaveStream(IO.File.OpenRead(waveFile)) stream.Volume = volume Using player As New SoundPlayer(stream) player.Play() End Using End Using End Sub Source: http://smdn.jp/programming/netfx/tips/set_volume_of_soundplayer/ Skorpro, Jitnaught and Bob_74 3 Link to comment Share on other sites More sharing options...
Skorpro Posted April 26, 2016 Share Posted April 26, 2016 Maybe it's useful too C++ (without volume control) // MP3void skpMP3(int iCommand, string strMP3Name, bool bSoundRepeat){ // iCommand: 1 = play // 0 = stop // 2 = pause // 3 = resume string strMP3Command; if (iCommand == 1) { strMP3Command = "open \"" + strMP3Name + "\" alias " + strMP3Name; mciSendStringA(strMP3Command.c_str(), NULL, 0, 0); if (bSoundRepeat == 0) strMP3Command = "play " + strMP3Name; else if (bSoundRepeat == 1) strMP3Command = "play " + strMP3Name + " repeat"; mciSendStringA(strMP3Command.c_str(), NULL, 0, 0); } else if (iCommand == 2) { strMP3Command = "pause " + strMP3Name; mciSendStringA(strMP3Command.c_str(), NULL, 0, 0); } else if (iCommand == 3) { strMP3Command = "resume " + strMP3Name; mciSendStringA(strMP3Command.c_str(), NULL, 0, 0); } else if (iCommand == 0) { strMP3Command = "stop " + strMP3Name; mciSendStringA(strMP3Command.c_str(), NULL, 0, 0); strMP3Command = "close " + strMP3Name; mciSendStringA(strMP3Command.c_str(), NULL, 0, 0); }}// WAVEvoid skpWAV(bool bCommand, string strWAVName, bool bSoundRepeat){ // bCommand: 1 = play // 0 = stop if (bCommand == 1) { if (bSoundRepeat == 0) PlaySoundA(strWAVName.c_str(), NULL, SND_ASYNC); else if (bSoundRepeat == 1) PlaySoundA(strWAVName.c_str(), NULL, SND_LOOP | SND_ASYNC); } else if (bCommand == 0) { PlaySoundA(NULL, 0, 0); }} Jitnaught and qiangqiang101 2 Link to comment Share on other sites More sharing options...
Recommended Posts
Create an account or sign in to comment
You need to be a member in order to leave a comment
Create an account
Sign up for a new account in our community. It's easy!
Register a new accountSign in
Already have an account? Sign in here.
Sign In Now