Quantcast

Jump to content

» «
Photo

Play External Wav file with Volume control without NAudio.dll or Bass.

1 reply to this topic
qiangqiang101
  • qiangqiang101

    I'm Not MentaL

  • Members
  • Joined: 02 Feb 2010
  • Malaysia

#1

Posted 26 April 2016 - 07:29 PM

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 System
Imports System.IO
Class 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 = 100
End 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/progr...of_soundplayer/

  • Skorpro and Jitnaught like this

Skorpro
  • Skorpro

    GTAholic

  • Members
  • Joined: 19 Jul 2009
  • Germany

#2

Posted 26 April 2016 - 08:04 PM

Maybe it's useful too :)

 

C++ (without volume control)

// MP3
void 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);
	}
}


// WAVE
void 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);
	}
}
  • qiangqiang101 and Jitnaught like this




1 user(s) are reading this topic

0 members, 1 guests, 0 anonymous users