Compress Wave Audio using CODECS
summary
Microsoft's Win95 and Winnt operating systems include compressed decompression WAVE streaming.
CODECS. Save your WAVE audio in compression not only can reduce storage space
Demand, can also reduce the time of data transmission when transmitting on the network.
This article and its included instance code tell you how to use Codecs installed in the Windows system
To compress and decompress the audio. Take a little slightly changed these code can be used as uncompressed compressed
Data, perform data format conversion. The attached example code is used in Microsoft Visual C 5.0
Version developed and tested in Win95 and Winnt 4.0 operating systems.
Introduction
Win95 and nearest Winnt have sounds that can be installed with installed CODECS processed WAVE format
The ability to frequency and video data streams.
A CODEC is a small segment for compression and decompression (Decompress)
According to the code of the stream (therefore, you are named CO-DEC). Many CODECs can compress and decompress.
Some CODECs can only be used to decompress, so private data can be played on the system, but
The data format cannot be created on the system.
Although a CODEC can be used for compression and decompression any of the data streams or designed
A variety of CODECs to achieve a high compression ratio, better fidelity or real-time compression
Performance to compress some data type. For example, get high video compressed data compression ratio
A good method is not necessarily the same effect when applied to audio data, but also.
This article focuses on how to use CODEC in your own code to use the audio data in your system CODECS
The supported manner is compressed. One main reason for compressed audio data is to reduce storage
The amount of data required for a sound sequence. Less data means less space occupied by the sound,
And it is possible to pass on MODEM and network at a faster speed. If the data is used in Windows
If a universal format supported is compressed, you can play directly if you don't have to handle it.
- The system will use its own CODECS to extract data and play.
What is the codecs in my system?
Win95 and Winnt itself have several standard CODECs, or it can be installed in the system.
Use the program to install other Codecs. For example, DSP Group, Inc. Truespeech Codec
Send with Win95, so anything you write to Win95 can apply this CODEC
(If the user does not delete it or prohibit it in the control panel). May be installed in the future
An example of CODEC is the audio data used by the Microsoft Network (MSN) software.
All installed CODECs are managed by the Audio Compression Manager (ACM). We can from a small program
Inquiries ACM to find what CODECs installed, they all support what format. You can also double
Click the multimedia option in the control panel, select the advanced tab, you can see the Codecs installed in the system.
Introduction Application ACM, I know a good way to do what it is managed every CODEC.
It is written a simple query ACM command line application. The CAPS program included in this article is over
It is this feature - let's take a look at its code, I will give you to analyze this procedure.
Explain what functionality every step is done.
First start from the included header file required to call the ACM programming interface:
#include
#include
#include
#include
#include
MMSystem.h header files set Windows to support most of multimedia features, but do not include ACM
Interfaces and any vendor definition. Mmreg.h contains definitions of formatted labels for various WAVE data types designed for different vendors. It also includes knots for processing different WAVE data types.
Definition of WaveForamTex). MSACM.H contains the API required for ACM, logo
and many more.
The first thing we have to do is to implement some common ACM queries to judge the version number, get it
As it currently manages information about how many drivers. Below is part of the code of the ACM:
// get the ACM version number
DWORD DWACMVER = acmgetversion ();
Printf ("ACM VERSION% u.%. 02u build% U",
HiWord (dwacmver) >> 8,
HiWord (dwacmver) & 0x00FF,
Loword (dwacmver);
IF (loword (dwacmver) == 0) Printf ("(Retail));
Printf ("/ n");
// Show some information about ACM
Printf ("ACM Metrics: / N");
DWORD DWCODECS = 0;
MmResult MMR = ACMMETRICS (NULL, ACM_METRIC_COUNT_CODECS, & DWCODECS);
IF (mmr) {
Show_ERROR (MMR);
}
Else {
Printf ("% Lu Codecs Installed / N", DWCODECS);
}
The Caps instance queries more ACM information. You can take a closer look at its code and run the program to know the result.
After the ACM has a simple understanding, you can now ask it to enumerate all current drivers in the system.
program. We use the callback function to report the callback function in the program.
Data, this is a very common method programming in Windows. The following call is enumeration
All devices managed by the current ACM:
// Enumerate all permissible drivers
Printf ("enabled drivers: / n");
MMR = ACMDRIVERENUM (DriveRenumProc, 0, 0);
IF (mmr) show_error (mmr);
Like other multimedia functions, many ACM function calls return a mmResult value, pointing out
Errors that can occur. This value is 0 indicates that the function is successfully executed. Now let's take a look at the enumeration
Tune DRIVERENUMPROC, which is called by each drive in the system:
Bool Callback DriveRenumProc (Hacmdriverid Hadid, DWORD DWInstance, DWORD FDWSUPPORT)
{
Printf ("ID:% 8.8LXH", HADID);
Printf ("supports: / n");
IF (FDWSupport & AcmdriverDetails_supportf_async) Printf ("async convers / n");
IF (FDWSupport & AcmdriverDetails_supportf_codec) Printf ("DiffERENT FORMAT Conversions / N);
IF (fdwsupport & acmdriverdetails_supportf_converter) Printf ("Same Format Conversions / N);
IF (fdwsupport & acmdriverdetails_supportf_filter) Printf ("Filtering / N"); // Get some specific information
Acmdriverdetails DD;
Dd.cbstruct = SizeOf (DD);
MmResult MMR = AcmdriverDetails (Hadid, & DD, 0);
IF (mmr) {
PRINTF (""); show_error (mmr);
}
Else {
Printf ("Short Name:% S / N", DD.SZSHORTNAME);
Printf ("Long Name:% S / N", DD.SZLONGNAME;
Printf ("CopyRight:% S / N", DD.SZCopyRight);
Printf ("Licensing:% S / N", DD.SZLICENSING;
Printf ("Features:% S / N", DD.SZFEATURES;
Printf ("Supports% u formats / n", dd.cformattags;
Printf ("Supports% U Filter Formats / N", DD.cfilTertags;
}
/ / Open the driver
Hacmdriver Had = NULL;
MMR = ACMDRIVEROPEN (& Had, Hadid, 0);
IF (mmr) {
PRINTF (""); show_error (mmr);
}
Else {
DWORD DWSIZE = 0;
MMR = ACMMETRICS (HAD, ACM_METRIC_MAX_SIZE_FORMAT, & DWSIZE);
IF (DWSIZE CBSIZE = LOWORD (DWSIZE) - SIZEOF (WAVEFormatex);
PWF-> wformattag = Wave_Format_unknown;
ACMFORMATDETAILS FD;
MEMSET (& fd, 0, sizeof (fd));
fd.cbstruct = SizeOf (FD);
fd.pwfx = pWF;
fd.cbwfx = dwsize;
fd.dwformattag = Wave_FORMAT_UNKNOWN;
MMR = ACMFORMATENUM (HAD, & FD, FORMATENUMPROC, 0, 0);
IF (mmr) {
Printf ("");
Show_ERROR (MMR);
}
Free (PWF);
Acmdriverclose (HAD, 0);
}
Return true; // Continue enumeration
}
The driver passes a set of flags that describe the types supported by the driver. Some drivers can operate asynchronously, while other drivers cannot be. Some drivers can convert a WAVE data format into another format (called CODECS), while others can only complete the filtering operation, which is the same as the input and output format. Note ACM maintains the names, copyright information of the driver, so we can get this data without loading or opening the specified driver. This is convenient, such as when you need to place the data in the list box is selected by the user.
To get more details about a certain driver capability, you must load the driver and open it, and can be implemented by calling the ACMOPENDRIVER. Once the driver is open, you can request enumerated WAVE data format it supported. At the same time, there is a small problem - although all WAVE format describes the WaveForamTex, many formats use this structure's extended form to save their specific information. If we want to enumerate all formats, you need to know how much for this structure is allocated to fill out the details of the details. The size of the desired structure can be obtained by passing the ACM_METRIC_MAX_SIZE_FORMAT flag to the ACMMETRICS function. If you have read the code above, you will find that I just simply convert the assigned space to the Waveformatex pointer. I only interested in common information instead of any particular type of data, so this pointer meets my requirements.
After allocating space for the structure, I can now enumerate the supported format. This time I use a backup function to get the relevant data of the enumerated format:
Bool Callback FormatenumProc (Hacmdriverid Hadid, LPACMMMATDETAILS PAFD,
DWORD DWINSTANCE, DWORD FDWSUPPORT)
{
Printf ("% 4.4LXH,% S / N", PAFD-> DWFORMATTAG, PAFD-> SZFORMAT);
Return true; // Continue enumeration
}
As you can see, this is an attempt and only print some of the formats.
In this way, through the above code, you can query all the drivers of the ACM to find each
The format supported by the driver. I suggest you run the CAPS program now, look at you.
What is installed on the system.
Use specific CODEC
Ok, we have learned what CodeCs installed on your system - now look at how to check
Find a particular CODEC and use it to compress audio data. Let us see the conv instance,
It uses a valid CODEC to compress a simple WAVE packet. In order to make the code more
Simply, I implemented it in the form of console applications, and I didn't try to play.
Corridged data or deposit it into the file. This instance's code is only showing you how to find you
Required drives and use it converts the data to a compressed format. Leave it to you.
Two steps to implement compression
In the ideal case, compressing some data may only say to the system: "This has some data.
Please compress into this format. "Unfortunately, Windows programming is far from the ideal, like usually one
We have to do many trivial work. The first thing to solve is also the most important question is to give
Set CODEC may not compress the data format you use. For example, we have entered some 11025Hz, 8 bits,
Mono PCM data (perhaps the user said to the microphone), this format is almost all
Multimedia PC can be recorded. We may have to pass the data through MODEM, so we want to be as possible
The compressed data makes the amount of data. We chose TrucSpeech Codec, which is installed
In Windows, the compression ratio of approximately 10: 1 can be obtained. The question we have to encounter is
TrueSpeech Codec does not handle 11025Hz, 8-bit, mono PCM data. It can only
Rather 8000Hz, 16-bit, mono data (8 bits in some cases). So we must first
The source data is converted to the intermediate PCM format supported by TrueSpeech Codec, and then it will be in it.
Inter-data conversion to the final desired format.
You can use a different CODEC distributed with Windows to convert a PCM format to another.
So you need to use some CODEC to convert the data to other CODEC to process formats. We have known how to enumerate the format that CODECS and its support, so this is achievable.
But there is still a problem, I ignore it in the instance code, leave you to solve it. If a CODEC can
Enough to create the compressed format we want, but support several different input formats, how do we choose
What is the best intermediate format? According to Nigel's guidelines, "always do the least amount of work", I
Select the first PCM format that uses CODEC supported. Because it is easy to implement, it may be guided
Data distortion. Suppose some CODEC we have to use has some nearly distortion compression algorithms,
Enough to receive 8-bit or 16-bit 11025 Hz or 22050 Hz PCM data. We have to convert at 441000 Hz,
16-bit stereo recording high-fidelity samples. We tried to reduce the amount of data without caution.
If we enumerate the format supported by this CODEC, the first result may be 11025Hz, 8-bit mono
Road format. Let me convert the data to this format, then compress, this is certain to lose one
Some quality because this intermediate format is not good enough. If you use 16 bits 22050 Hz, it will be better. Already
Tell you this shortcomings, let us look at the CONV instance, see how it works.
Conv instance program
CONV instances are divided into four phases: it creates some samples of WAVE format data, find a suitable CODEC,
Transform data to this CODEC processed intermediate format, and finally convert data into the desired format. in order to
Simply, the source data program creates instead of entry or read from the WAVE file:
// First, we create a Wave in the WAVE that is just recorded in the format, 11.025kHz.
// 8-bit mono PCM, this is an entry format available on all machines, our example
// The child is a 1-second long 1kHz sine wave Wave, just 1000 cycles
WAVEFORMATEX WFSRC;
MEMSET (& WFSRC, 0, SIZEOF (WFSRC));
Wfsrc.cbsize = 0;
Wfsrc.wformattag = Wave_format_pcm; // pcm
Wfsrc.nchannels = 1; // mono
Wfsrc.nsamplespergec = 11025; // 11.025 kHz
Wfsrc.wbitsPersample = 8; // 8 bit
Wfsrc.nblockAlign = wfsrc.nchannels * wfsrc.wbitsPersample / 8;
Wfsrc.navgbytespersec = wfsrc.nsamplespersec * wfsrc.nblockalign;
DWORD dwsrcsamples = wfsrc.nsamplespespec;
BYTE * psrcdata = new byte [dwsrcsamples]; // 1 second length
BYTE * PDATA = Psrcdata;
Double f = 1000.0;
Double Pi = 4.0 * Atan (1.0);
Double W = 2.0 * pi * f;
For (DWORD DW = 0; DW
The above code creates a WAVEFormatex structure to describe the source data format and use simple
The mathematics method has generated 1
The second half of 11.025 kHz, 8-bit mono PCM WAVE data.
The next step is to choose to convert data to what format and select a suitable CODEC.
Word wformattag = Wave_format_dspgroup_truespeech; // Now we have selected a CODEC that supports the target format tag
HACMDRIVERID HADID = FIND_DRIVER (WFORMATTAG);
IF (hadid == null) {
Printf ("No Driver Found / N);
Exit (1);
}
Printf ("Driver Found (Hadid:% 4.4LXH / N", Hadid);
The Find_Driver function enumerates all drivers until a driver that supports a given tag value (this example is
Wave_format_dspgroup_truespeech). I have not given this code because it is in front of the enumeration
The code is very similar. You can then see how it works.
The driver is selected, and now you have to create a Waveformatex to the resulting compressed data format for the final driver.
Structure, and generate a WAVEFORMATEX structure for the intermediate PCM format used for the driver.
// Get the details of the format
// Note: This is just the first or most likely format for a given format.
Waveformatex * pwfdrv = get_driver_format (hadid, wformattag);
IF (pwfdrv == null) {
Printf ("Error getting format info / n");
Exit (1);
}
Printf ("Driver Format:% U BITS,% Lu Samples Per Second / N",
PWFDRV-> WBITSPERSPERSPLE, PWFDRV-> NSAMPLESPERSEC);
/ / Get the PCM format tag supported by the driver
// Note: We just choose the first supported PCM format but not necessarily the best choice.
Waveformatex * pwfpcm = get_driver_format (Hadid, Wave_Format_PCM);
IF (pWFPCM == null) {
Printf ("Error getting PCM Format Info / N);
Exit (1);
}
Printf ("PCM Format:% U BITS,% Lu Samples Per Second / N",
PWFPCM-> WBITSPERSPLE, PWFPCM-> NSAMPLESPERSEC);
It is a bit repeated. It is important to note that the get_driver_format function only enumerates the first matching format - may not be available
Possible best quality.
Now we have a WAVEFormatex structure description source format, intermediate PCM format, and final compression format. Can start turn
Data. The conversion is achieved by an object called the ACM. We can open the stream, pass the source format, target format to it,
Require it for conversion.
Be careful here if synchronous conversion is time consuming if CODEC's algorithm is complicated. Some CODEC can work asynchronously, through
The window sends a message, or calls a callback function, or set an event to inform you to the conversion process. The following code is
At least troubleshoot, complete task - you have to wait until it is completed. There is another point, it is very important. As you know, let's fight
Open switch, indicate the ACM_STREAMOPENF_NONREALTIME flag. This is very important. If you omit this mark, then some
Drivers (such as TRUESPEECH drivers) will report an error 512 (meaning is not possible). This error tells you what you want
The conversion of seeking cannot be performed in real time. There is no such problem in my instance code, but if you try to convert large amounts of data while playing data, you should pay attention to this.
Let's take a look at the conversion of the first step, it is done to convert the source data into an intermediate format:
/
// convert the source Wave to the PCM format supported by CODEC
// We use any of the converted drivers that enable PCM format
Hacmstream HSTR = NULL;
MMR = ACMSTREAMOPEN (& HSTR,
Null, // Any driver
& wfsrc, // source format
PWFPCM, // Target format
Null, // No filter
Null, // Did not call
0, // instance data (unused)
ACM_STREAMOPENF_NONREALTIME); // Sign
IF (mmr) {
Printf ("Failed to Open A Stream to Do PCM To PCM Conversion / N);
Exit (1);
}
/ / Open a buffer for the result of the conversion
DWORD DWSRCBYTES = dwsrcsamples * wfsrc.wbitsPersample / 8;
DWORD DWDST1SAMPLES = dwsrcsamples * pwfpcm-> nsamplespersperspec / wfsrc.nsamplespespec;
DWORD DWDST1BYTES = DWDST1SAMPLES * PWFPCM-> WBITSPERSAMPLE / 8;
BYTE * pdst1data = new byte [dwdst1bytes]; // Fill in the conversion information
ACMSTreamheader strHDR;
MEMSET (& strHDR, 0, SIZEOF (STRHDR));
strHdr.cbstruct = SizeOf (strHDR);
strHDr.pbsrc = psrcdata; // Source data to be converted
Strhdr.cbsrclength = dwsrcbytes;
strHDr.pbdst = pdst1data;
strHDr.cbdstlength = dwdst1bytes; // Prepare the head
MMR = ACMSTREAMPREPAREHEADER (HSTR, & strHDR, 0); // Conversion Data
Printf ("Converting to Intermediate PCM Format ... / N");
MMR = ACMSTREAMCONVERT (HSTR, & STRHDR, 0);
IF (mmr) {
Printf ("Failed to Do PCM To PCM Conversion / N");
Exit (1);
}
Printf ("CONVERTED OK / N");
// Close the flow
AcmstreamClose (HSTR, 0);
When the current is turned on, the second parameter is NULL, indicating that any driver is transformed. Complex only is calculated to be output
Data allocate how large buffers. Due to the conversion between the PCM format does not involve compression and decompression, it is calculated directly.
You may notice that ACMSTREAMPREPAREHEADER is called, which arranges everything for the driver and allows the driver before conversion.
Lock memory.
The final step is to convert the intermediate format to the final compression format:
///
/ / Convert intermediate format to the final compression format
/ / Open the driver
Hacmdriver Had = NULL;
MMR = ACMDRIVEROPEN (& Had, Hadid, 0);
IF (mmr) {
Printf ("failed to open driver / n"); exit (1);
}
// Open the conversion stream
// Note Use the ACM_STREAMOPENF_NONREALTIME flag.
// Without this flag Some software compression will report the 512 error - ie
MMR = ACMSTREAMOPEN (& HSTR,
Had, // Driver handle
PWFPCM, // Source Format
PWFDRV, // Target format
NULL, / /
NULL, // Non-return function
0, // instance data (unused)
ACM_STREAMOPENF_NONREALTIME); // Sign
IF (mmr) {
Printf ("Failed to Open A Street to Do Pcm To Driver Format Conversion / N");
Exit (1);
}
/ / Assign a buffer for the conversion result
/ / According to the size of the output buffer according to the average rate of bytes
/ / Plus a one-action position (bit)
/ / No extra space IMA_ADPCM driver will not be converted
DWORD DWDST2BYTES = PWFDRV-> NAVGBYTESPERSEC * DWDST1SAMPLES /
PWFPCM-> nsamplespersec;
DWDST2BYTES = dwdst2bytes * 3/2; // Add a point of space
BYTE * pdst2data = new byte [dwdst2bytes]; // Fill in the conversion information
ACMSTreamHeader strHDR2;
MEMSET (& strHDR2, 0, SIZEOF (strHDR2));
strHdr2.cbstruct = sizeof (strHDR2);
strHDr2.pbsrc = pdst1data; // To convert source data
Strhdr2.cbsrclength = dwdst1bytes;
strHDr2.pbdst = pdst2data;
strHDr2.cbdstlength = dwdst2bytes; // Prepare the head
MMR = ACMSTREAMPREPAREHEADER (HSTR, & strHDR2, 0); // Conversion Data
Printf ("Converting to Final Formal ... / N");
MMR = ACMSTREAMCONVERT (HSTR, & strHDR2, 0);
IF (mmr) {
Printf ("Failed to Do Pcm To Driver Format Conversion / N");
Exit (1);
}
Printf ("CONVERTED OK / N");
// Close flow and driver
MMR = acmstreamclose (HSTR, 0);
MMR = acmdriverclose (HAD, 0);
The above conversion is very similar to the PCM format, but this time we offer it to open the flow.
The handle of the driver. In fact,
NULL can still be used here, because this driver has been presented, but provides a handle to avoid
Save time to find us
This driver is.
Calculating the size of the buffer for compressed data is a bit difficult, requiring it to guess. Waveformatex knot
The NavgBytespeSec domain represents the average rate of reading bytes during playback. We can use it
It is estimated that storage compressed Wave needs to have much space. The data given by some drivers is indeed average,
Instead of the worst case, I choose to increase the space of 50%. This method is in practice
Some waste but very effective. Once the conversion is completed, the CBDStLengthused domain of the ACMStreamHeader's structure indicates how many bytes actually used. I use it to calculate the compression ratio:
// Display conversion statistics
Printf ("Source Wave Had% Lu Bytes / N", DWSRCBYTES;
Printf ("Converted Wave Has% Lu Bytes / n", strHDr2.cbdstlength;
Printf ("Compression Ratio IS% F / N", (Double) DWSRCBYTES /
(Double) strHdr2.cbdstlength;
to sum up
Compress Wave format data is easy to use using the CODECS attached to the Windows operating system and makes data occupying less storage.
The transmission time is shorter. If you have your own compression format, you can create and install your own CODEC, using it as the code here.