おせわになっています。けじゅです。
「スライダーを2つ配置すると、コンパイルはできるが実行されない」
とう内容の続きで、新たな問題が発生しました。
スライダーをボリュームの変わりに使っていますが。最初音を鳴らすと、ボリュームが
「0」なのに音がでてしまいます。スライダーをクリックすると音は0になり、上にド
ラッグしてくと音は大きくなります。最初0なのに音をでなくするにはどうしたらよい
のでしょうか?
環境は VC++6.0 MFC windowXP です。
あなたがどんなコードを書いているのかわからないのでアドバイスのしようがありませ
ん。
せめてサウンドを再生しているところのコードくらい載せてくださいな
すみませんシャノンさん 関係しているところをのせました。
①は、マウスがスライダーをコントロールするためのクラスです。
②は、音量を調整する関数です
③は、MIDIでメロディーを出力する関数です
④はボタンを押したときにMIDIで「ファ」を出力するクラスです。
今回④を実行したときにスライダーの音量は「0」なのに、最初音が出てしまいます。
そしてスライダーをクリックすると音はきえます。最初から音量が0になる方法をおし
えてください。
//①
void CVcdoremiDlg::OnVScroll(UINT nSBCode, UINT nPos, CScrollBar* pScrollBar)
{
int x,y;
UpdateData(TRUE);
x=m_sldr.GetPos();
y=m_sldr1.GetPos();
volume(x);
//pan(y);
UpdateData(FALSE);
CDialog::OnVScroll(nSBCode, nPos, pScrollBar);
}
//②
void volume(int x)
{
MMRESULT ret;
DWORD dwMsg;
x=127-x;
dwMsg = 0x0007B0+ x* 0x10000;
ret = midiOutShortMsg(hMidiOut, dwMsg);
}
//③
void midi_play(int doremi) //ドレミを出す
{
MMRESULT ret;
DWORD dwMsg;
dwMsg = 0x7F3C90 + doremi * 0x100; //オン
ret = midiOutShortMsg(hMidiOut, dwMsg);
}
//④
void CVcdoremiDlg ::OnButton4() // [ふぁ]
{
midi_play(5);
}
セル=けじゅ です。
プログラム起動時に volume が呼ばれてないため、最初はスライダーが 0 というのがボ
リュームに反映されてないせいだと思われます。
OnInitDialog で volume を呼んでやりませう。
OnInitDialog()の所にm_sldr.GetPos();とvoid volume();を追加しましたが変化なっか
たです。ボタンをおしてMIDIの音を鳴らすとスライダーの位置は0なのに音がでてしまい
う。ボタンを押す前にスライダーをクリックすれば、音は出ない。
アドバイスおねがいします。
BOOL CVcdoremiDlg::OnInitDialog()
{
CDialog::OnInitDialog();
// バージョン情報... メニュー項目をシステム メニューへ追加します。
// IDM_ABOUTBOX はコマンド メニューの範囲でなければなりません。
ASSERT((IDM_ABOUTBOX & 0xFFF0) == IDM_ABOUTBOX);
ASSERT(IDM_ABOUTBOX < 0xF000);
CMenu* pSysMenu = GetSystemMenu(FALSE);
if (pSysMenu != NULL)
{
CString strAboutMenu;
strAboutMenu.LoadString(IDS_ABOUTBOX);
if (!strAboutMenu.IsEmpty())
{
pSysMenu->AppendMenu(MF_SEPARATOR);
pSysMenu->AppendMenu(MF_STRING, IDM_ABOUTBOX,
strAboutMenu);
}
}
// このダイアログ用のアイコンを設定します。フレームワークはアプリケー
ションのメイン
// ウィンドウがダイアログでない時は自動的に設定しません。
SetIcon(m_hIcon, TRUE); // 大きいアイコンを設定
SetIcon(m_hIcon, FALSE); // 小さいアイコンを設定
// TODO: 特別な初期化を行う時はこの場所に追加してください。
m_sldr.SetRange(0,127);
m_sldr.SetTicFreq(10);
m_sldr.SetPageSize(5);
m_sldr.SetLineSize(20);
m_sldr.SetPos(127);
m_sldr.GetPos();
void volume();
if(midi_set()==0) EndDialog(IDCANCEL); //■追加
return TRUE; // TRUE を返すとコントロールに設定したフォーカスは失われ
ません。
}
キツい口調になってしまうことを最初にお詫びしておきます。
確かに私は
>OnInitDialog で volume を呼んでやりませう。
と言いましたが、あなたはご自分の書いた
>m_sldr.GetPos();
>void volume();
このコードの意味を理解してらっしゃいますか?
GetPos で取得した値はどこにも保存されていませんし、volume には有効な値が渡され
ていません。さて、この2行にどれほどの意味があるんでしょうか…
惜しいところまで行ってます。
敢えて解答は書きませんので、もう少し頑張ってみてください。
お世話になっています。
シャノンさん「OnInitDialog」のところに下記のように書きましたが ビルドして実行
してみましたが、変化ないです。 宜しくお願いします。
int x;
x=m_sldr.GetPos( );
void volume(int x);
>void volume(int x);
なんかツッコミたくなりますが、まぁ写しミスでしょうかね。
そうするってぇと…しばしお待ちを。
こっちでも同じプログラムを組んで試してみるとしましょう
hMidiOutは取得しなくて良いものなのですか?
どこかのヘッダに固定値入っているの?
volumeのところのmidiOutShortMsg戻り値は正常に
「MMSYSERR_NOERROR」になってますか
ちょっと気になること
>void volume(int x);
関数呼び出すのに一々「void」っているの?
MIDIデバイスって初期化のいないデバイスなの?
> if(midi_set()==0) EndDialog(IDCANCEL); //■追加
これって何のための処理なの?
思うにMFCで組んだ時にそれぞれのメッセージハンドラが
どういうタイミング呼ばれるか、どういう順番でコールされていくか
と言った部分が良く理解できていないような気がします。
この辺の部分がわからない状態で行き当たりばったりにプログラムを組んでも
結局、自分の首を絞めるだけです。
メッセージハンドラがどんなタイミングで呼ばれているかを確認するだけなら
簡単なテストアプリを作ってTRACE文を入れてみるとか、デバッガーで止めてみるとか
すれば、簡単に確認できるので自分で実践される事をお勧めします。
今回の場合、ボリュームの初期設定をしていないのが原因ですが、
初期設定が必要なのはわかっているのだけれど、どこで書いて良いのかわからないのと
初期設定が必要な事自体がわかっていないのとでは雲泥の差があります。
基本的にプログラムは自分で書いた処理しか走りません。
問題なのはMFCでカプセルかされてしまって表に出てこないけれど、処理されている
部分でしょうねぇ。多分、はじめたばかり人はMFCで勝手にやってくれる部分と
自分でコードを書かねばならない部分の区切りが良く理解できないのでしょうね。
この辺って、Win32SDKでプログラミングした事が無いとわからないかもしれないですね。
どの辺までがWindowsプログラミングの定型的な部分で、
どの辺までが作成者に任されている部分なのかとか。
似たようなアプリを作ってみましたが、ちゃんと音量が最小の時は音が出ないようにな
ってますよ。
>hMidiOutは取得しなくて良いものなのですか?
>どこかのヘッダに固定値入っているの?
>MIDIデバイスって初期化のいないデバイスなの?
たしかに初期化するコードは入っていませんが、音は出ているようですからここに書い
てないだけで初期化はしてるんじゃないでしょうか。…しててくださいよ。
>「OnInitDialog」のところに下記のように書きましたが
>x=m_sldr.GetPos( );
この戻り値がちゃんと 127 になっていますか?
ありがとうございます。シャノンさん、一つチェックしてほしいことがありますが、
アプリを実行したら、最初に音をならすボタンを押したら鳴りますでしょか?何回かためしても
らえないでしょうか? いつもいろいろなアドバイスありがとうございます。
シャノンさんが作ってくれたのは、似たようなアプリであって
けじゅさんが作ったアプリと同じものではないわけなので
シャノンさんのアプリで試しても意味が無いと思いますよ。
あなたが書いたコードと全く同じコードではないと思いますし。
あと、コード的に以下の部分は無駄だと思います。
m_sldr.SetPos(127);
x = m_sldr.GetPos();
volume(x);
初期値を定数定義して以下のようにした方がすっきりします。
static const int sciInitVolume = 127;
m_sldr.SetPos(sciInitVolume);
volume(sciInitVolume);
スライダーコントロールのGetPosを呼ぶ意味が無いです。
値はわかっているわけなのでそのまま設定すれば良いだけです。
あと、数値を直接プログラムに埋め込むのはやめて定数定義を使いましょう。
C++言語の入門書にこの辺の説明があるはずです。
急がば回れとも言います。基礎を固めた方があとあと役に立ちます。
MIDIデバイスの初期化処理をどこでどのように行っているか明確に
答えてもらってないのですが?
私の言いたいことは
> if(midi_set()==0) EndDialog(IDCANCEL); //■追加
が初期化処理してませんかと言うことです
この行以前までの関数呼び出しに対してそれぞれ成功ステータスが返って
きていれば何らかの状況変化が望めると思います
なんら変化が見れないのであれば、それを無効化しているものが存在するはずです