VB.NETでmp3またはwmaで録音するには?

解決


You  2004-11-01 14:01:43  No: 117313  IP: [192.*.*.*]

現在VB.NET(2003)、WindowsXPという環境でMCIのMMControlを使って音声をwavファイルに録音しています。
ファイル転送の際にファイルサイズが大きいのでmp3かwmaファイルにエンコードしようと思い、vbmp3.dllやlame393.dllを使ってみたのですが、VB6上では動いたのですがVB.NETでは動作してくれませんでした。

まず、VB.NETで上記のDLL使えたよ、という方がいたらサンプルソース等あれば教えていただきたいのです。
もしくは使用可能であったDLL等、あれば情報頂けるとありがたいです。
その際、wavファイルでの録音にこだわっているわけではないので、エンコードでなく直接mp3やwmaに録音できても全然問題はありません。

ご存知の方いらっしゃいましたらよろしくお願いいたします。

編集 削除
raki  URL  2004-11-01 18:36:01  No: 117314  IP: [192.*.*.*]

VB6ではどのように使っていますか?
Declare宣言で?それとも参照設定 or CreateObjectで?

VB6で使えてVB.NETで使えないというのは、
大体宣言部が怪しいのですが。

差し支えなければコードを載せていただけませんか?
もしかしたらなぜ動かないのか分かると思います。

編集 削除
You  2004-11-02 10:26:58  No: 117315  IP: [192.*.*.*]

ありがとうございます。
1日経ってしまいましたが。
たとえばVBMP3.DLLですとサンプルソースの通りにDeclareで以下のように宣言しています。

Public Class clsMP3

    '** 基本操作系 **
    Declare Function vbmp3_init Lib "VBMP3.dll" () As Boolean
    Declare Function vbmp3_free Lib "VBMP3.dll" () As Boolean
    Declare Function vbmp3_open Lib "VBMP3.dll" (ByVal pszName As String, ByVal pInfo As InputInfo) As Boolean
    Declare Function vbmp3_close Lib "VBMP3.dll" () As Boolean
    Declare Function vbmp3_play Lib "VBMP3.dll" () As Boolean
    Declare Function vbmp3_stop Lib "VBMP3.dll" () As Boolean
    Declare Function vbmp3_pause Lib "VBMP3.dll" () As Boolean
    Declare Function vbmp3_restart Lib "VBMP3.dll" () As Boolean
    Declare Function vbmp3_seek Lib "VBMP3.dll" (ByVal sec As Long) As Boolean
    Declare Function vbmp3_setPlayFrames Lib "VBMP3.dll" (ByVal frames As Long) As Boolean
    Declare Function vbmp3_setPlayFramesExVB Lib "VBMP3.dll" (ByVal frames As Double) As Boolean
    Declare Function vbmp3_setPlaySamples Lib "VBMP3.dll" (ByVal samples As Long) As Boolean
    Declare Function vbmp3_setPlaySamplesExVB Lib "VBMP3.dll" (ByVal samples As Double) As Boolean
    Declare Function vbmp3_reload Lib "VBMP3.dll" () As Boolean
    '** VBMP3 関連 **
    Declare Function vbmp3_getVersion Lib "VBMP3.dll" () As Long
    Declare Function vbmp3_setVbmp3Option Lib "VBMP3.dll" (ByVal pVbmp3Option As VBMP3_OPTION) As Boolean
    Declare Sub vbmp3_getVbmp3Option Lib "VBMP3.dll" (ByVal pVbmp3Option As VBMP3_OPTION)
    Declare Function vbmp3_setDecodeOption Lib "VBMP3.dll" (ByVal pDecOption As DEC_OPTION) As Boolean
    Declare Sub vbmp3_getDecodeOption Lib "VBMP3.dll" (ByVal pDecOption As DEC_OPTION)
    Declare Sub vbmp3_setWaveOutDeviceId Lib "VBMP3.dll" (ByVal id As Long)
    '** エンコード系 **
    Declare Function vbmp3_encodeOpen Lib "VBMP3.dll" (ByVal pszWaveName As String, ByVal pWaveForm As WAVE_FORM) As Boolean
    Declare Function vbmp3_encodeStart Lib "VBMP3.dll" (ByVal pszMp3Name As String) As Boolean
    Declare Function vbmp3_encodeStop Lib "VBMP3.dll" () As Boolean
    Declare Function vbmp3_getEncodeState Lib "VBMP3.dll" (ByVal readSize As Long, ByVal encodeSize As Long) As Long

    Public Structure VBMP3_OPTION
        Public inputBlock As Long              '入力フレーム数[Default = 40]
        Public outputBlock As Long             '出力フレーム数[Default = 30]
        Public inputSleep As Long              '入力直後のスリープ時間(ミリ秒)[Default = 5]
        Public outputSleep As Long             '出力直後のスリープ時間(ミリ秒)[Default = 0]
    End Structure

    Public Structure DEC_OPTION
        Public reduction As Long               'サンプリング 0:1/1 1:1/2 2:1/4 [Default = 0]
        Public convert As Long                 'チャンネル 0:ステレオ 1:モノラル[Default = 0]
        Public freqLimit As Long               '周波数[Default = 24000]
    End Structure

    Public Structure WAVE_FORM
        Public channels As Long                'チャンネル数
        Public bitsPerSample As Long           'ビット数/1サンプル
        Public samplingRate As Long            'サンプリングレート
        Public dataSize As Long                'ファイルサイズ
    End Structure

    Public Structure InputInfo
        Public szTrackName As String            '曲名
        Public szArtistName As String           'アーティスト名
        Public channels As Long                 'チャンネル数
        Public bitrate As Long                  'ビットレート(kbit/s)
        Public samplingRate As Long             'サンプルレート(Hz)
        Public TotalSec As Long                 '演奏時間(s)
    End Structure

    Public Function EncodeTest() As Boolean

        Dim pWaveForm As New WAVE_FORM
        Dim outFile As String
        Dim mp3Enc As New clsMP3
        outFile = "test.mp3"

        If clsMP3.vbmp3_encodeOpen(Trim("test.wav"), pWaveForm) Then
            Debug.WriteLine(pWaveForm)
            Call clsMP3.vbmp3_encodeStart(outFile)
        End If

    End Function
End Class

エンコードスタートの前に必ずオープンすること、とあったのですが、encodeopen関数にて("wavファイル",構造体)でフルパス、ファイル名のみでカレントディレクトリに設置、共にFalseが帰ってきます。
もう少しOpen関数についても調べてみます。

編集 削除
You  2004-11-02 10:30:23  No: 117316  IP: [192.*.*.*]

すみません、最後のEncodeTest()の中のclsmp3を参照しているのはミスです。
mp3Enc.vbmp3_encodeOpen(〜、ですね。
それでもやっぱりFalseではありますけれど。

編集 削除
raki  URL  2004-11-02 11:07:56  No: 117317  IP: [192.*.*.*]

VBMP3.dllをDLして、サンプルを覗いてみました(VB6の)。
それと上記コードを見比べてみた所、いくつか気になった点が。
VB.NETのアップグレード機能を使わず、手動で書き換えたと思われますが、
以下の修正を加えてみて下さい。

①変数の型をVB.NET用に書き換えてください。
  Long⇒Integer

②構造体の宣言に<StructLayout(LayoutKind.Sequential)>を加えて下さい。
例)
<StructLayout(LayoutKind.Sequential)> _
Public Structure VBMP3_OPTION
  ・・・

③VB.NETでサイズ指定のStringを使用する場合
InputInfo構造体のszTrackNameメンバはVB6ではサイズ指定のStringのため、
VB.NETでは以下のように宣言してください。

<VBFixedString(128), _
System.Runtime.InteropServices.MarshalAs( _
System.Runtime.InteropServices.UnmanagedType.ByValTStr, _
SizeConst:=128)> _
Public szTrackName As String

他も同様に。上記のは
String * 128 の場合なので、
String * 256 などの場合は、上記の 128 を指定サイズに変えて下さい。

④Declare宣言を以下のようにしてみて下さい。
Declare Auto Function 〜
Declare Auto Sub 〜
または、
Declare Ansi Function 〜
Declare Ansi Sub 〜

まずはこれだけ試してもらえますか?

編集 削除
You  2004-11-02 13:23:43  No: 117318  IP: [192.*.*.*]

わざわざ調べていただいた上にご丁寧な解説までありがとうございます。
下記の通りやってみました。

①について全置換し、Imports System.Runtime.InteropServicesを記述して②〜④をやってみたのですが・・・
やはりencodeOpenでFalseが帰ってきてしまいます。
なんだか普通に根本的な使い方を間違っている気もしてきました。
もう少し調べつつやってみます。

#StructLayoutをはじめて知った時点で勉強不足だとしか言いようが無いですが・・・

編集 削除
raki  URL  2004-11-02 13:45:54  No: 117319  IP: [192.*.*.*]

ダメでしたか。とすれば、もう一つだけ修正をお願いします。
VB6で関数の引数に ByVal, ByRef が指定できますが、
これを省いた場合、VB6とVB.NETで意味が違います。
VB6の場合、ByRefが標準ですが、VB.NETの場合、ByValが標準です。

最初のソースを見ると、全て ByVal 指定になっていますが、
おそらくVB6のソースを単純にコピー&ペーストしたときに、
VB.NETが勝手に省略されているものに ByVal と付けてしまったと
思われます。

このため、VB6のサンプルソースと見比べながら、
VB6で ByRef が省略されているものには
明示的に ByRef を指定してください。

もしかしたら、これが原因かもしれません。
(違うかもしれませんが)

編集 削除
raki  URL  2004-11-02 14:21:31  No: 117320  IP: [192.*.*.*]

追記:
EncodeTest関数がどこで呼ばれているか分かりませんが、
vbmp3_encodeOpen を呼び出す前に、
vbmp3_init でDLLを初期化していますか?
これを行った所、私のところでは
vbmp3_encodeOpen は通りました。
もちろん、終了前に vbmp3_free を呼び出して、
メモリを解放することを忘れないで下さい。

#ただ、私の場合、使用したWAVEファイルが悪かったのか、
#VB6でもVB.NETでも vbmp3_encodeStart をコールしたのに
#うんともすんとも言わなかったんですけどね(T T)

編集 削除
You  2004-11-02 14:23:37  No: 117321  IP: [192.*.*.*]

またもやありがとうございます。
encodeOpenで引っかかっているので、特にencodeOpenには気をつけて全て修正したのですが・・・
ダメでした。
もうやーめたっと、というのが好きでないため、もうちょっと色々といじってみます。
どうしてもできそうになかったら一応解決にしておきますが、なんとかして本当の解決に持っていってみます。
せめてOpenでTrueが帰ってくるまでは。

もしお気づきの点が他にもあれば、ぜひよろしくお願いいたします。

編集 削除
raki  URL  2004-11-02 14:50:53  No: 117322  IP: [192.*.*.*]

レス時刻が2分違いの為、私の追記に気づかれているのか不安・・・
ということで、再度レスを。

vbmp3_init での初期化と
vbmp3_free での解放は行っていますか?

詳しくは先の私のレスを。
これを行っても、ダメだったというのであれば、
今の私にはちょっと分かりません。
仕事が終わったらまとまった時間を作って調べてみることも出来ますが。

頑張って下さい。

編集 削除
You  2004-11-02 16:37:34  No: 117323  IP: [192.*.*.*]

お仕事中なのに何度もありがとうございます。
vbmp3_init()は起動時にしているのですが、やはり通りません。
そう考えると根本的に使い方(.NETのコーディングとして)が間違っているぽいです。
それをクリアした上で今度は実際にエンコードしてくれる関数の動作、という事になりそうです。
もう少し頑張ってみます。

編集 削除
raki  URL  2004-11-02 17:43:59  No: 117324  IP: [192.*.*.*]

すみません、一つ謝らなければいけないことが・・・
自分の動いたソースを見直してみた所、
Declare Function 〜
に Auto も Ansi もつけていませんでした。
(自分で修正をお願いしておきながら・・・)
で、Auto をつけてみた所、通りませんでした・・・(- -;;
何も指定しないか、Ansi を指定した場合に上手く行くようです。

先のレスの④の修正を全て元に戻すか、
Ansi で修正を加えてください。

申し訳ありませんでした。m(_ _)m
以下にテストしたソースを載せておきます。
参考までに。

Imports System.Runtime.InteropServices

Public Class Class1
    Public Shared Sub Main()
        Dim aaa As New clsMP3
        aaa.EncodeTest()
    End Sub
End Class

Public Class clsMP3
    'VisualBasic用 MP3操作DLL 関数宣言ファイル
    '** 基本操作系 **
    Declare Ansi Function vbmp3_init Lib "VBMP3.dll" () As Boolean
    Declare Ansi Function vbmp3_free Lib "VBMP3.dll" () As Boolean

    '** エンコード系 **
    Declare Ansi Function vbmp3_encodeOpen Lib "VBMP3.dll" (ByVal pszWaveName As String, ByRef pWaveForm As WAVE_FORM) As Boolean
    Declare Ansi Function vbmp3_encodeStart Lib "VBMP3.dll" (ByVal pszMp3Name As String) As Boolean
    Declare Function vbmp3_encodeStop Lib "VBMP3.dll" () As Boolean
    Declare Function vbmp3_getEncodeState Lib "VBMP3.dll" (ByRef readSize As Integer, ByRef encodeSize As Integer) As Integer

    '<StructLayout(LayoutKind.Sequential)> _
    Public Structure WAVE_FORM
        Public channels As Integer              'チャンネル数
        Public bitsPerSample As Integer         'ビット数/1サンプル
        Public samplingRate As Integer          'サンプリングレート
        Public dataSize As Integer              'ファイルサイズ
    End Structure

    Public Function EncodeTest() As Boolean
        Dim pWaveForm As New WAVE_FORM
        Dim outFile As String

        outFile = "C:\test.mp3"

        Call vbmp3_init()

        If vbmp3_encodeOpen(Trim("C:\test.wav"), pWaveForm) Then
            Call vbmp3_encodeStart(outFile)
        End If

        Call vbmp3_free()
    End Function
End Class

編集 削除
You  2004-11-04 11:58:37  No: 117325  IP: [192.*.*.*]

わざわざお教え頂いてるのに謝られてしまってはこちらの申し訳が立たないです。

Ansiで試したところ、encodeOpenではTrueが帰り、pWaveFormに情報が格納されていました。ありがとうございます。
そしてencodeStartではFalseが帰ってくる状況は同じです。
今も色々試してはいるのですが・・・

編集 削除
raki  URL  2004-11-05 12:09:52  No: 117326  IP: [192.*.*.*]

まずはVB6のサンプルプログラムを使って、
正常にエンコードが行われるかを確かめてみてはいかがでしょうか。

使用したWAVEファイルが悪いのか、コードの記述が悪いのかを
まず切り分けることが先だと思います。

編集 削除
You  2004-12-03 14:30:20  No: 117327  IP: [192.*.*.*]

大変遅くなりましたが、やっとのことで出来ました…

結論として、MMControlコンポーネントで録音したwavファイルは使用不可でした。
APIですと16bitステレオが作成可能で、これをwmaエンコードすることに成功しました。

ただしこれはWAV2WMA.DLLのケースで、vbmp3に関しては結局わからずじまいです。
ひょっとしたら同じ原因かもしれませんが、ちょっと今からまたvbmp3サンプルを作る時間がないのです。

恐らくvbmp3でもエンコードできるとは思うのですが、現在は疲れ果てたのでこれにて…
vbmp3のコーディングミスであった可能性もありますが、vb6とほぼ同条件で組めたとは思っていたのですが…

色々とありがとうございました。
vbmp3での実験に成功したら、コードを貼りに来たいと思います。

編集 削除