📄 soundply.cpp
字号:
// ObjectWindows - (C) Copyright 1992 by Borland International
/* This example demonstrates the use of MCI APIs in Windows 3.1 in an OWL
* application:
*
* You must have a sound board/Speaker and its device driver installed under
* Windows 3.1 and be certain that it works -- Use the sound applet in Windows
* Control Pannel to generate a sound. You may copy one of the .WAV files from
* the WINDOWS subdirectory in your system to this example's subdirectory.
*
* Run the .EXE. Choose File:Open and select a .WAV file. Choose Control:Play
* to play the waveform. The Control menu lets you stop/play/pause and resume.
* The scrollbar allows random access through the waveform while it is playing.
* This example demonstrates the use of the MCI API and a callback via
* WM_MCINOTIFY.
*/
#include <string.h>
#include <stdio.h>
#include <owl.h>
#include <filedial.h>
#include <button.h>
#include <scrollba.h>
#include <math.h>
#include <mmsystem.h>
#include "soundply.h"
#define ID_SCROLL 150 // Scroll bar
#define TIMER_ID 264 // Unique timer ID.
// The waveform device opened.
WORD wDeviceID = 0;
BOOL flushNotify = FALSE;
class TSoundBar : public TScrollBar
{
private:
int waveRatio;
LONG waveLength;
char elementName[255];
void RePosAndPlay (LONG newPos);
public:
TSoundBar(PTWindowsObject AParent, int AnId, int X, int Y, int W,
int H, BOOL IsHScrollBar, PTModule AModule = NULL) :
TScrollBar(AParent, AnId, X, Y, W, H, IsHScrollBar, AModule) {};
void ScrollSetInfo (int wRatio, LONG wLength);
void ScrollSetName (char *eName);
virtual void SBLineUp(RTMessage Msg) = [NF_FIRST + SB_LINEUP];
virtual void SBLineDown(RTMessage Msg) = [NF_FIRST + SB_LINEDOWN];
virtual void SBPageUp(RTMessage Msg) = [NF_FIRST + SB_PAGEUP];
virtual void SBPageDown(RTMessage Msg) = [NF_FIRST + SB_PAGEDOWN];
virtual void SBThumbPosition(RTMessage Msg) = [NF_FIRST + SB_THUMBPOSITION];
virtual void SBTop(RTMessage Msg) = [NF_FIRST + SB_TOP];
virtual void SBBottom(RTMessage Msg) = [NF_FIRST + SB_BOTTOM];
};
// Define a class derived from TApplication
class TSoundApp :public TApplication
{
public:
TSoundApp(LPSTR AName, HINSTANCE hInstance, HINSTANCE hPrevInstance,
LPSTR lpCmdLine, int nCmdShow)
: TApplication(AName, hInstance, hPrevInstance, lpCmdLine, nCmdShow) {};
virtual void InitMainWindow();
};
_CLASSDEF(TSoundWindow)
class TSoundWindow : public TWindow
{
private:
char elementName[255];
int running;
int pause;
UINT timeGoing;
int waveRatio;
LONG waveLength;
TSoundBar *tScroll;
MCI_GENERIC_PARMS MciGenParm;
MCI_OPEN_PARMS MciOpenParm;
MCI_PLAY_PARMS MciPlayParm;
MCI_STATUS_PARMS MciStatusParm;
MCI_SET_PARMS MciSetParm;
void GetDeviceInfo ();
void StopWave ();
void StopMCI ();
public:
TSoundWindow (PTWindowsObject Parent, LPSTR Title);
~TSoundWindow ();
void UpdateSoundWindow ();
virtual void GetWindowClass (WNDCLASS &WndClass);
virtual void SetupWindow();
virtual LPSTR GetClassName ();
virtual void MciNotify (RTMessage Msg) = [WM_FIRST + MM_MCINOTIFY];
virtual void Paint (HDC PaintDC, PAINTSTRUCT _FAR &PaintInfo);
virtual void FileOpen (RTMessage Msg) = [CM_FIRST + SM_OPEN];
virtual void FileExit (RTMessage Msg) = [CM_FIRST + SM_EXIT];
virtual void PlayWave (RTMessage Msg) = [CM_FIRST + SM_PLAY];
virtual void PauseWave (RTMessage Msg) = [CM_FIRST + SM_PAUSE];
virtual void HelpAbout (RTMessage Msg) = [CM_FIRST + SM_ABOUT];
virtual void IdleStuff (RTMessage Msg) = [WM_FIRST + WM_TIMER];
};
void TSoundBar::RePosAndPlay (LONG newPos)
{
MCI_PLAY_PARMS MciPlayParm;
MCI_SEEK_PARMS MciSeekParm;
MCI_SET_PARMS MciSetParm;
MCI_OPEN_PARMS MciOpenParm;
MCI_GENERIC_PARMS MciGenParm;
// Only allow SEEK if playing.
if (!wDeviceID)
return;
// Close the currently playing wave.
flushNotify = TRUE;
MciGenParm.dwCallback = 0L;
mciSendCommand (wDeviceID, MCI_STOP, MCI_WAIT, (DWORD)(LPMCI_GENERIC_PARMS)&MciGenParm);
mciSendCommand (wDeviceID, MCI_CLOSE, MCI_WAIT, (DWORD)(LPMCI_GENERIC_PARMS)&MciGenParm);
// Open the wave again and seek to new position.
MciOpenParm.dwCallback = 0L;
MciOpenParm.wDeviceID = wDeviceID;
MciOpenParm.wReserved0 = 0;
MciOpenParm.lpstrDeviceType = NULL;
MciOpenParm.lpstrElementName = elementName;
MciOpenParm.lpstrAlias = NULL;
if (mciSendCommand (wDeviceID, MCI_OPEN, MCI_WAIT| MCI_OPEN_ELEMENT,
(DWORD)(LPMCI_OPEN_PARMS)&MciOpenParm)) {
MessageBox (HWindow, "Open Error", "Sound Play", MB_OK);
return;
}
wDeviceID = MciOpenParm.wDeviceID;
// Our time scale is in SAMPLES.
MciSetParm.dwTimeFormat = MCI_FORMAT_SAMPLES;
if (mciSendCommand (wDeviceID, MCI_SET, MCI_SET_TIME_FORMAT,
(DWORD)(LPMCI_SET_PARMS)&MciSetParm)) {
MessageBox (HWindow, "Set Time Error", "Sound Play", MB_OK);
return;
}
// Compute new position, remember the scrollbar range has been scaled based on waveRatio.
MciSeekParm.dwCallback = NULL;
MciSeekParm.dwTo = ((newPos * waveRatio) > waveLength) ? waveLength : (newPos * waveRatio);
if (mciSendCommand (wDeviceID, MCI_SEEK, MCI_TO,
(DWORD)(LPMCI_SEEK_PARMS)&MciSeekParm)) {
MessageBox (HWindow, "Seek Error", "Sound Play", MB_OK);
return;
}
MciPlayParm.dwCallback = (unsigned long)HWindow;
MciPlayParm.dwFrom = 0;
MciPlayParm.dwTo = 0;
if (mciSendCommand (wDeviceID, MCI_PLAY, MCI_NOTIFY,
(DWORD) (LPMCI_PLAY_PARMS)&MciPlayParm)) {
MessageBox (HWindow, "Play Error", "Sound Play", MB_OK);
return;
}
}
void TSoundBar::ScrollSetInfo (int wRatio, LONG wLength)
{
waveRatio = wRatio;
waveLength = wLength;
}
void TSoundBar::ScrollSetName (char *eName)
{
strcpy (elementName, eName);
}
void TSoundBar::SBLineUp(RTMessage msg)
{
TScrollBar::SBLineUp (msg);
RePosAndPlay (GetPosition ());
}
void TSoundBar::SBLineDown(RTMessage msg)
{
TScrollBar::SBLineDown (msg);
RePosAndPlay (GetPosition ());
}
void TSoundBar::SBPageUp(RTMessage msg)
{
TScrollBar::SBPageUp (msg);
RePosAndPlay (GetPosition ());
}
void TSoundBar::SBPageDown(RTMessage msg)
{
TScrollBar::SBPageDown (msg);
RePosAndPlay (GetPosition ());
}
void TSoundBar::SBThumbPosition(RTMessage msg)
{
TScrollBar::SBThumbPosition (msg);
RePosAndPlay (GetPosition ());
}
void TSoundBar::SBTop(RTMessage msg)
{
TScrollBar::SBTop (msg);
RePosAndPlay (GetPosition ());
}
void TSoundBar::SBBottom(RTMessage msg)
{
TScrollBar::SBBottom (msg);
RePosAndPlay (GetPosition ());
}
// Construct the THelloApp's MainWindow data member
void TSoundApp::InitMainWindow()
{
MainWindow = new TSoundWindow(NULL, "OWL SoundPlay Demo ... using MCI");
}
int PASCAL WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
LPSTR lpCmdLine, int nCmdShow)
{
TSoundApp SoundApp ("SoundApp", hInstance, hPrevInstance, lpCmdLine,
nCmdShow);
SoundApp.HAccTable = LoadAccelerators (hInstance, "ACCELERATORS_1");
SoundApp.Run();
return SoundApp.Status;
}
// Construct the TSoundWindow
TSoundWindow::TSoundWindow (PTWindowsObject Parent, LPSTR Title) :
TWindow (Parent, Title)
{
AssignMenu (ID_MENU);
Attr.X = 50;
Attr.Y = 100;
Attr.W = 400;
Attr.H = 150;
running = 0;
pause = 0;
waveLength = waveRatio = 0;
elementName[0] = '\0';
tScroll = new TSoundBar (this, ID_SCROLL, 50, 67, 300, 0, TRUE);
}
void TSoundWindow::SetupWindow()
{
TWindow::SetupWindow();
tScroll->SetRange (0, 0);
}
TSoundWindow::~TSoundWindow ()
{
StopMCI ();
}
// Paint member function
void TSoundWindow::Paint (HDC PaintDC, PAINTSTRUCT _FAR &)
{
char buffer[100];
// File name.
if (lstrlen (elementName))
TextOut (PaintDC, 5, 5, elementName, lstrlen(elementName));
else
TextOut (PaintDC, 5, 5, "<No WAVEFORM file loaded>", 25);
TextOut (PaintDC, 160, 35, "Samples:", 8);
TextOut (PaintDC, 50, 48, "0", 1); // Beginning value.
// Ending number of samples.
if (waveLength)
sprintf (buffer, "%d", waveLength * waveRatio);
else
strcpy (buffer, "Unknown");
TextOut (PaintDC, 315, 48, buffer, lstrlen (buffer));
}
// GetClassWindow member
void TSoundWindow::GetWindowClass (WNDCLASS &WndClass)
{
TWindow::GetWindowClass(WndClass);
}
// GetClassName member
LPSTR TSoundWindow::GetClassName ()
{
return "SoundPlay";
}
void TSoundWindow::GetDeviceInfo ()
{
WAVEOUTCAPS wOutCaps;
if (!waveOutGetDevCaps (wDeviceID, (LPWAVEOUTCAPS)&wOutCaps,
sizeof (wOutCaps))) {
MessageBox (HWindow, "GetDevCaps Error", "Sound Play", MB_OK);
return;
}
}
// Play the wave...
void TSoundWindow::PlayWave (RTMessage)
{
if (!running) {
// MCI APIs to open a device and play a .WAV file, using
// notification to close
MciOpenParm.dwCallback = 0L;
MciOpenParm.wDeviceID = 0;
MciOpenParm.wReserved0 = 0;
MciOpenParm.lpstrDeviceType = NULL;
MciOpenParm.lpstrElementName = elementName;
MciOpenParm.lpstrAlias = NULL;
if (mciSendCommand (0, MCI_OPEN, (DWORD) (MCI_WAIT | MCI_OPEN_ELEMENT),
(DWORD)(LPMCI_OPEN_PARMS)&MciOpenParm)) {
MessageBox (HWindow,
"Open Error - a waveForm output device is necessary to use this demo.",
"Sound Play", MB_OK);
return;
}
wDeviceID = MciOpenParm.wDeviceID;
// The time format in this demo is in Samples.
MciSetParm.dwCallback = 0L;
MciSetParm.dwTimeFormat = MCI_FORMAT_SAMPLES;
if (mciSendCommand (wDeviceID, MCI_SET, MCI_SET_TIME_FORMAT,
(DWORD)(LPMCI_SET_PARMS)&MciSetParm)) {
MessageBox (HWindow, "SetTime Error", "Sound Play", MB_OK);
return;
}
MciPlayParm.dwCallback = (unsigned long)HWindow;
MciPlayParm.dwFrom = 0;
MciPlayParm.dwTo = 0;
mciSendCommand (wDeviceID, MCI_PLAY, MCI_NOTIFY,
(DWORD) (LPMCI_PLAY_PARMS)&MciPlayParm);
// Modify the menu to toggle PLAY to STOP, and enable PAUSE.
HMENU hMenu = GetMenu (HWindow);
ModifyMenu (hMenu, SM_PLAY, MF_STRING, SM_PLAY, "&Stop");
EnableMenuItem (hMenu, SM_PAUSE, MF_ENABLED);
// Make sure the Play/Stop toggle menu knows we're running.
running = TRUE;
// Start a timer to show our progress through the waveform file.
timeGoing = SetTimer (HWindow, TIMER_ID, 500, NULL);
// Give enough information to the scrollbar to monitor the
// progress and issue a re-MCI_OPEN.
tScroll->ScrollSetName (elementName);
} else
StopWave ();
}
void TSoundWindow::PauseWave (RTMessage)
{
if (!pause) {
// Pause the playing.
MciGenParm.dwCallback = 0L;
mciSendCommand (wDeviceID, MCI_PAUSE, MCI_WAIT,
(DWORD)(LPMCI_GENERIC_PARMS)&MciGenParm);
// Toggle Pause menu to Resume.
HMENU hMenu = GetMenu (HWindow);
ModifyMenu (hMenu, SM_PAUSE, MF_STRING, SM_PAUSE, "&Resume\tCtrl+R");
pause = TRUE;
} else {
// Resume the playing.
MciGenParm.dwCallback = 0L;
mciSendCommand (wDeviceID, MCI_RESUME, MCI_WAIT,
(DWORD)(LPMCI_GENERIC_PARMS)&MciGenParm);
// Toggle Resume menu to Pause.
HMENU hMenu = GetMenu (HWindow);
ModifyMenu (hMenu, SM_PAUSE, MF_STRING, SM_PAUSE, "P&ause\tCtrl+P");
pause = FALSE;
}
}
void TSoundWindow::StopMCI ()
{
if (timeGoing) // Timer running, then kill it now.
timeGoing = !KillTimer (HWindow, TIMER_ID);
// Stop playing the waveform file and close the waveform device.
MciGenParm.dwCallback = 0L;
mciSendCommand (wDeviceID, MCI_STOP, MCI_WAIT,
(DWORD)(LPMCI_GENERIC_PARMS)&MciGenParm);
mciSendCommand (wDeviceID, MCI_CLOSE, MCI_WAIT,
(DWORD)(LPMCI_GENERIC_PARMS)&MciGenParm);
running = FALSE;
wDeviceID = 0;
}
void TSoundWindow::StopWave ()
{
if (wDeviceID) {
StopMCI ();
// Reset the menus to Play menu and gray the Pause menu.
HMENU hMenu = GetMenu (HWindow);
ModifyMenu (hMenu, SM_PLAY, MF_STRING, SM_PLAY, "&Play\tCtrl+P");
ModifyMenu (hMenu, SM_PAUSE, MF_STRING | MF_GRAYED, SM_PAUSE, "P&ause\tCtrl+A");
}
}
void TSoundWindow::FileOpen (RTMessage)
{
char FileName[MAXPATH];
if ( GetApplication()->ExecDialog(new TFileDialog(this, SD_FILEOPEN, strcpy(FileName, "*.WAV"))) == IDOK )
if (CanClose()) {
// Remember the waveform file to open.
strcpy (elementName, FileName);
// Turn the Play menu on.
HMENU hMenu = GetMenu (HWindow);
EnableMenuItem (hMenu, SM_PLAY, MF_ENABLED);
waveLength = 0;
waveRatio = 0;
tScroll->SetPosition (0);
UpdateSoundWindow ();
}
}
void TSoundWindow::FileExit (RTMessage)
{
CloseWindow ();
}
// Response function MM_MCINOTIFY message when MCI_PLAY is complete.
void TSoundWindow::MciNotify (RTMessage)
{
int loVal, hiVal;
if (!flushNotify) { // Internal STOP/CLOSE, from thumb re-pos?
StopWave ();
// Make sure the thumb is at the end. There could be some WM_TIMER messages on the queue when
// we kill it, thereby flushing WM_TIMER's from the message queue.
tScroll->GetRange (loVal, hiVal);
tScroll->SetPosition (hiVal);
}
flushNotify = FALSE; // Yes, so ignore the close.
}
void TSoundWindow::UpdateSoundWindow ()
{
RECT r;
// First time it's different update the scroll bar numbers.
GetClientRect (HWindow, &r);
InvalidateRect (HWindow, &r, TRUE);
}
void TSoundWindow::HelpAbout (RTMessage)
{
MessageBox (HWindow, "SoundPly loads and plays waveform sound \
files (*.WAV). The features of this demo are Play/Stop, Pause/Resume, \
and random seeks through the file via the scollbar (while the sound is \
playing). NOTE: SoundPly will only play sounds if the machine contains \
a waveForm Multimedia device, e.g. SoundBlaster, etc.).",
"About Sound Play", MB_OK);
}
void TSoundWindow::IdleStuff (RTMessage)
{
if (!flushNotify) { // Internal STOP/CLOSE, from thumb re-pos?
MciStatusParm.dwCallback = 0L; // No, normal close.
MciStatusParm.dwItem = MCI_STATUS_LENGTH;
mciSendCommand (wDeviceID, MCI_STATUS, MCI_STATUS_ITEM, (DWORD)(LPMCI_STATUS_PARMS)&MciStatusParm);
if (waveLength != MciStatusParm.dwReturn) {
// First time it's different update the scroll bar numbers.
UpdateSoundWindow ();
waveLength = MciStatusParm.dwReturn;
}
// Compute the length and ratio and update tScroll info.
waveRatio = (int)ceill((waveLength / 32000) + .5);
tScroll->ScrollSetInfo (waveRatio, waveLength);
tScroll->SetRange (0, (int)(waveLength / waveRatio));
// Update the current position.
MciStatusParm.dwCallback = 0L;
MciStatusParm.dwItem = MCI_STATUS_POSITION;
mciSendCommand (wDeviceID, MCI_STATUS, MCI_STATUS_ITEM, (DWORD)(LPMCI_STATUS_PARMS)&MciStatusParm);
tScroll->SetPosition ((int)(MciStatusParm.dwReturn / waveRatio));
}
flushNotify = FALSE; // Yes, ignore this close.
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -