You are on page 1of 11

Using CODECs to Compress Wave Audio

By Nigel Thompson 4 April 97

Abstract
Windows 95 and Windows NT both include CO !Cs which can compress and decompress wa"e audio streams# $a"ing your wa"e audio data in compressed %orm can help with data storage re&uirements and reduce data transmission times when audio is sent o"er a networ'# This article and its accompanying sample code shows how to compress wa"e audio pac'ets using any o% CO !Cs installed on a Windows system# By altering the code "ery slightly it can also be used to decompress compressed data or per%orm data %ormat con"ersions# The sample code was de"eloped using (isual C)) "ersion 5#* and tested under Windows 95 and Windows NT 4#*

Introduction
Windows 95 and more recently Windows NT both include the ability to handle compressed wa"e%orm audio and "ideo data streams using installable CO !Cs# A CO !C is a small piece o% code used to COmpress or !Compress a data stream +hence CO, !C-# The data can represent anything such as audio or "ideo# .ost CO !Cs handle both compression and decompression but some are designed only to decompress so that proprietary data can be played on a system but the data %ormat cannot be created on that system# Although a CO !C can be used in principal to compress or decompress any stream o% data/ "arious CO !Cs ha"e been designed to compress certain data types with either higher compression ratios/ better %idelity or real,time per%ormance# 0or e1ample/ the best way to get a high degree o% "ideo data compression may not gi"e ade&uate results when applied to audio data and "ise "ersa# This article %ocuses on how to use a CO !C %rom your own code to compress audio data into one o% the %ormats supported by the CO !Cs on your system# The primary reason %or compressing audio data is to reduce the "olume o% data re&uired to store a sound se&uence# $maller data "olumes mean less dis' space is occupied by the sounds and also that they can be transmitted %aster o"er a modem or networ' lin'# 2% the data is compressed into one o% the common %ormats supported by Windows systems then it can be played bac' directly without the need to decompress it manually 3 the system will use its own CO !Cs to decompress the data %or playbac'#

Copyright 4 Nigel Thompson 5997

6age 5

What CODECs are in my system?


Windows 95 and Windows NT come complete with a number o% standard CO !Cs and can ha"e others installed by applications which are installed on the system# 0or e1ample the $6 7roup8s True$peech CO !C ships with Windows 95 so any program you write can be sure that this CO !C is going to be a"ailable +pro"iding the user hasn8t remo"ed it or disabled it using the Control 6anel-# An e1ample o% a CO !C which might be installed later is the one that the .icroso%t Networ' +.$N- so%tware uses %or its own audio data# All the installed CO !Cs are managed by the Audio Compression .anager +AC.-# We can %ind out what CO !Cs are installed/ and what %ormats each o% them supports by &uerying the AC. %rom a simple program# 9ou can also use the Control 6anel and loo' in the .ultimedia applet under the Ad"anced tab to see a list o% the installed CO !Cs on your system# Writing a simple command line program to &uery the AC. pro"ides a good introduction to dealing with the AC. and e1amining what each CO !C it manages can do# The CA6$ program that accompanies this article does :ust that so let8s ha"e a loo' at the code and 28ll e1plain what each step does as we go through it# ;et8s begin by loo'ing at what header %iles we need to include to be able to call the AC. A62s<

#include #include #include #include #include

<windows.h> <mmsystem.h> <mmreg.h> // Multimedia registration <msacm.h> // Audio Compression Manager <stdio.h>

The mmsystem#h header de%ines most o% the multimedia support %or Windows but not the AC. A62 set or any o% the manu%acturer speci%ic de%ines# .mreg#h contains de%initions o% wa"e %ormat tags %or "arious wa"e data types as designed by di%%erent manu%acturers# 2t also contains de%initions o% structures +based on WA(!0O=.AT!>- that are used to manipulate the di%%erent wa"e data types# The msacm#h %ile contains the A62s/ %lags and so on %or the Audio Compression .anager +AC.-# The %irst thing we can do is per%orm some general &ueries o% the AC. to get its "ersion number and in%ormation such as how many dri"ers it is currently managing# ?ere@s part o% the code that &ueries the AC.<

// get the ACM version DWO D dwACM!er " acm#et!ersion$%& print'$(ACM version )u.).*+u ,uild )u(./WO D$dwACM!er% >> 0./WO D$dwACM!er% 1 *2**334OWO D$dwACM!er%%& i' $4OWO D$dwACM!er% "" *% print'$( $ etail%(%& print'$(5n(%& // show some ACM metrics print'$(ACM metrics65n(%& DWO D dwCodecs " *&

Copyright 4 Nigel Thompson 5997

6age A

MM 7894: mmr " acmMetrics$;944- ACM<M7: /C<CO9;:<COD7C8- 1dwCodecs%& i' $mmr% = show<error$mmr%& > else = print'$()lu codecs installed5n(- dwCodecs%& > The CA6$ sample &ueries the AC. %or a %ew more metrics# 9ou can loo' at the code in detail and run the sample to see the results %or yoursel%# ?a"ing loo'ed at the AC./ we can now as it to enumerate all o% the dri"ers currently in the system# As is common practice in Windows programming the enumeration %unction we call uses a callbac' %unction in our code to report data %or each enumerated de"ice# ?ere8s the call that begins the enumeration o% all the de"ices currently managed by the AC.<

// enumerate the set o' ena,led drivers print'$(7na,led drivers65n(%& mmr " acmDriver7num$Driver7num?roc- *- *%& i' $mmr% show<error$mmr%& ;i'e many other multimedia %unctions/ most o% the AC. %unction calls return an ..=!$B;T "alue which indicates any error that might occur# A Cero "alue indicates that the %unction call completed success%ully# Now let8s see the enumeration callbac' %unction DriverEnumProc which is called %or each dri"er in the system<

@OO4 CA44@ACA Driver7num?roc$.ACMD /!7 /D hadid- DWO D dw/nstance- DWO D 'dw8upport% = print'$( id6 )0.0l2.(- hadid%& print'$( supports65n(%& i' $'dw8upport 1 ACMD /!7 D7:A/48<89??O :3<A8B;C% print'$( async conversions5n(%& i' $'dw8upport 1 ACMD /!7 D7:A/48<89??O :3<COD7C% print'$( di''erent 'ormat conversions5n(%& i' $'dw8upport 1 ACMD /!7 D7:A/48<89??O :3<CO;!7 :7 % print'$( same 'ormat conversions5n(%& i' $'dw8upport 1 ACMD /!7 D7:A/48<89??O :3<3/4:7 % print'$( 'iltering5n(%& // get some details ACMD /!7 D7:A/48 dd& dd.c,8truct " siCeo'$dd%& MM 7894: mmr " acmDriverDetails$hadid- 1dd- *%& i' $mmr% = print'$( (%& show<error$mmr%& > else = print'$( 8hort name6 )s5n(- dd.sC8hort;ame%& print'$( 4ong name6 )s5n(- dd.sC4ong;ame%& print'$( Copyright6 )s5n(- dd.sCCopyright%& print'$( 4icensing6 )s5n(- dd.sC4icensing%& print'$( 3eatures6 )s5n(- dd.sC3eatures%& print'$( 8upports )u 'ormats5n(- dd.c3ormat:ags%& print'$( 8upports )u 'ilter 'ormats5n(- dd.c3ilter:ags%&

Copyright 4 Nigel Thompson 5997

6age D

> // open the driver .ACMD /!7 had " ;944& mmr " acmDriverOpen$1had- hadid- *%& i' $mmr% = print'$( (%& show<error$mmr%& > else = DWO D dw8iCe " *& mmr " acmMetrics$had- ACM<M7: /C<MAD<8/E7<3O MA:- 1dw8iCe%& i' $dw8iCe < siCeo'$WA!73O MA:7D%% dw8iCe " siCeo'$WA!73O MA:7D%& // 'or M8F?CM WA!73O MA:7DG pw' " $WA!73O MA:7DG% malloc$dw8iCe%& memset$pw'- *- dw8iCe%& pw'F>c,8iCe " 4OWO D$dw8iCe% F siCeo'$WA!73O MA:7D%& pw'F>w3ormat:ag " WA!7<3O MA:<9;A;OW;& ACM3O MA:D7:A/48 'd& memset$1'd- *- siCeo'$'d%%& 'd.c,8truct " siCeo'$'d%& 'd.pw'2 " pw'& 'd.c,w'2 " dw8iCe& 'd.dw3ormat:ag " WA!7<3O MA:<9;A;OW;& mmr " acm3ormat7num$had- 1'd- 3ormat7num?roc- *- *%& i' $mmr% = print'$( (%& show<error$mmr%& > 'ree$pw'%& acmDriverClose$had- *%& > > return : 97& // continue enumeration

The callbac' %unction is passed a set o% %lags which describe what 'ind o% support the dri"er has# $ome dri"ers can operate asynchronously while other s do not# $ome dri"ers can con"ert one wa"e data %ormat to another +these are CO !Cs- and other dri"ers can only per%orm %iltering operations where the input and output %ormats are the same# Note that the AC. maintains this data along with the te1t name o% the dri"er/ copyright in%ormation and so on so that we can loo' at this data without the need to load or open a speci%ic dri"er# This is con"enient when we want to present a list bo1 to the user +%or e1ample- to select a speci%ic dri"er to use# To obtain more detailed in%ormation about the capabilities o% a dri"er/ we must load the dri"er and open it which is done by calling acmOpenDriver# Once the dri"er is open/ we can as' it to enumerate the wa"e data %ormats it supports# There is one minor complication here because although all wa"e %ormat description structures are based on WAVEFO !A"E# many %ormats use an e1tended %orm o% the structure to hold in%ormation speci%ic to the structure# 2% we want to enumerate all the %ormats we need some idea o% how big a structure to allocate so the dri"er can %ill in the details# We can %ind the siCe o% the largest structure re&uired by calling acm!etrics and passing the AC!$!E" IC$!A#$%I&E$FO !A" %lag# 2% you loo' at the code abo"e you8ll see 2 simply cast the result o% the allocation to be a WAVEFO !A"E# pointer# 28m not interested in any type,speci%ic data here :ust the common in%ormation so this pointer does all 2 need#

Copyright 4 Nigel Thompson 5997

6age 4

?a"ing allocated the structure/ 2 can now call acmFormatEnum to enumerate the supported %ormats# Once again we use a callbac' %unction to recei"e the enumerated %ormat data<

@OO4 CA44@ACA 3ormat7num?roc$.ACMD /!7 /D hadid- 4?ACM3O MA:D7:A/48 pa'd- DWO D dw/nstance- DWO D 'dw8upport% = print'$( )H.HlD.- )s5n(- pa'dF>dw3ormat:ag- pa'dF>sC3ormat%& return : 97& // continue enumerating

>

As you can see/ this one8s tri"ial and :ust prints out some o% the in%ormation about the %ormat# $o with the code abo"e you can &uery the AC. %or all its dri"ers and %ind what %ormats are supported by each# 2 suggest you run the CA6$ program now and see what your system currently has installed#

Using a %peci'ic CODEC


OE/ so we8"e seen how to %ind out what CO !Cs are installed on your system/ now let8s see how we locate a speci%ic CO !C and use it to compress some audio data# We8re going to loo' at the CON( sample now which compresses a simple wa"e data pac'et using one o% the a"ailable CO !Cs# To 'eep the code as simple as possible 2 implemented it in a console application and ha"e mad no attempt to either play the compressed data or sa"e it to a %ile# The sample code simply shows how to %ind the dri"er you need and get it to con"ert the data into a compressed %orm# The rest/ as we say/ is up to you#

Doing the compression t(o)step


2n the ideal world compressing some data would be simply a case o% saying to the system< F?ere8s some data/ compress it in this %ormat pleaseF# Bn%ortunately/ the Windows programming world is %ar %rom ideal and as usual we get to do a lot o% the grunt wor' oursel"es# The %irst and most important problem to sol"e arises because o% the %act that any gi"en CO !C may not be able to compress the data %ormat you :ust happen to be wor'ing in# 0or e1ample/ let8s say that we record some data +perhaps the user spea'ing into a microphone- at 55#*A5 '?C/ G bit/ mono/ 6C./ which is a %ormat all .ultimedia 6Cs can record in# We8d li'e to send this message to a relati"e "ia modem so we want to compress it as much as possible to get the data siCe down# 9ou choose to use the True$peech CO !C which comes with Windows and can achie"e something li'e 5*<5 compression# The problem you immediately come up against is that the True$peech CO !C can8t handle 55#*A5 '?C/ G bit/ mono 6C. data# 2t can only handle G#*** '?C/ 5H bit/ mono 6C. +or G bit in some cases-# $o what we ha"e to do is %irst con"ert the source data into an intermediate 6C. %ormat the True$peech CO !C can handle/ then we can get the True$peech CO !C to con"ert the intermediate data to the %inal %ormat we need# Con"erting one 6C. %ormat to another can be done using a di%%erent CO !C that also ships with Windows so what we need to do is use one CO !C to con"ert the data to the %ormat the other CO !C can handle# 7i"en that we 'now how to enumerate the CO !Cs and their supported %ormats/ this loo's reasonable#

Copyright 4 Nigel Thompson 5997

6age 5

There is howe"er one %urther problem which 2 chose to ignore in my sample code and 28ll lea"e to you to resol"e# 2% we ha"e a CO !C that will create the compressed %ormat we want but supports se"eral input %ormats/ how do we choose the best intermediate %ormat to useI 0ollowing Nigel8s ma1im which states< FAlways do the least amount o% wor' possibleF 2 chose to simply use the %irst 6C. %ormat the CO !C supports as the intermediate %orm# While this is "ery easy to implement it can lead to some loss o% data %idelity# Consider that the CO !C we want to use has some algorithm %or almost lossless compression and can accept G or 5H bit 6C. data at 55#*A5 or AA#*5*# ;et8s say we want to con"ert a high %idelity sample recorded at 44#5 '?C/ 5H bit stereo# What we are trying to do is reduce the data "olume but not at the e1pense o% &uality# 2% we simply enumerate the %ormats the CO !C supports/ the %irst one we %ind might well be 55#*A5 '?C/ G bit# .ono# 2% we con"ert to this %ormat %irst and then compress it we will certainly ha"e lost some &uality because the intermediate %ormat we chose was not good enough# 2% we8d ha"e used 5H bit and AA '?C/ we would ha"e done much better# ?a"ing warned you o% this pit%all/ let8s loo' now at the CON( sample and see how it wor's#

"he CO*V samp+e app+ication


The CON( sample wor's in %our stages< it creates some sample wa"e%orm data/ locates a suitable CO !C/ con"erts the data to an intermediate %orm the CO !C can handle and %inally con"erts it to the re&uired %orm# 0or simplicity/ the source data is created programmatically rather than by a li"e recording or reading a #WA( %ile<

// // // // //

3irst we create a wave that might have ,een Iust recorded. :he 'ormat is JJ.*+K L.C- 0 ,it mono ?CM which is a recording 'ormat availa,le on all machines. our sample wave will ,e J second long and will ,e a sine wave o' JL.C which is e2actly J-*** cycles

WA!73O MA:7D w'8rc& memset$1w'8rc- *- siCeo'$w'8rc%%& w'8rc.c,8iCe " *& w'8rc.w3ormat:ag " WA!7<3O MA:<?CM& // pcm w'8rc.nChannels " J& // mono w'8rc.n8amples?er8ec " JJ*+K& // JJ.*+K L.C w'8rc.w@its?er8ample " 0& // 0 ,it w'8rc.n@locLAlign " w'8rc.nChannels G w'8rc.w@its?er8ample / 0& w'8rc.nAvg@ytes?er8ec " w'8rc.n8amples?er8ec G w'8rc.n@locLAlign& DWO D dw8rc8amples " w'8rc.n8amples?er8ec& @B:7G p8rcData " new @B:7 Mdw8rc8amplesN& // J second duration @B:7G pData " p8rcData& dou,le ' " J***.*& dou,le pi " H.* G atan$J.*%& dou,le w " +.* G pi G '& 'or $DWO D dw " *& dw < dw8rc8amples& dwOO% = dou,le t " $dou,le% dw / $dou,le% w'8rc.n8amples?er8ec& GpDataOO " J+0 O $@B:7%$J+P.* G sin$w G t%%& > A WAVEFO !A"E# structure is created to describe the source data %ormat and a wa"e o% one second duration 55#*A5 '?C/ mono/ G bit 6C. is generated with some simple math#

Copyright 4 Nigel Thompson 5997

6age H

The ne1t step is to choose a %ormat we8d li'e to con"ert the data to and locate a suitable CO !C#

WO D w3ormat:ag " WA!7<3O MA:<D8?# O9?<: 978?77C.& // ;ow we locate a COD7C that supports the destination 'ormat tag .ACMD /!7 /D hadid " 'ind<driver$w3ormat:ag%& i' $hadid "" ;944% = print'$(;o driver 'ound5n(%& e2it$J%& > print'$(Driver 'ound $hadid6 )H.HlD.%5n(- hadid%& The 'ind$driver %unction enumerates all the dri"ers until it %inds one that supports the gi"en tag "alue +int his case WA(!J0O=.ATJ $67=OB6JT=B!$6!!C?-# 2 won8t show the details since it8s "ery similar to the enumeration code we loo'ed at earlier# 9ou can e1amine how it wor's %or yoursel% later# ?a"ing located the dri"er we now need to construct a WAVEFO !A"E# structure %or the %inal compressed data %ormat that the dri"er will generate and also %or the intermediate 6C. %ormat the dri"er needs as input<

// get the details o' the 'ormat // ;ote6 this is Iust the 'irst o' one or more possi,le 'ormats 'or the given tag WA!73O MA:7DG pw'Drv " get<driver<'ormat$hadid- w3ormat:ag%& i' $pw'Drv "" ;944% = print'$(7rror getting 'ormat in'o5n(%& e2it$J%& > print'$(Driver 'ormat6 )u ,its- )lu samples per second5n(pw'DrvF>w@its?er8ample- pw'DrvF>n8amples?er8ec%& // get a ?CM 'ormat tag the driver supports // ;ote6 we Iust picL the 'irst supported ?CM 'ormat which might not really // ,e the ,est choice. WA!73O MA:7DG pw'?CM " get<driver<'ormat$hadid- WA!7<3O MA:<?CM%& i' $pw'?CM "" ;944% = print'$(7rror getting ?CM 'ormat in'o5n(%& e2it$J%& > print'$(?CM 'ormat6 )u ,its- )lu samples per second5n(pw'?CMF>w@its?er8ample- pw'?CMF>n8amples?er8ec%& At the ris' o% repeating mysel%/ beware that the get$driver$'ormat %unction :ust enumerates %or the %irst matching %ormat and this might not be optimal i% you want the best possible &uality# Now we ha"e WAVEFO !A"E# structures built to describe the source %ormat/ the intermediate 6C. %ormat and the %inal compressed %ormat# 2t8s time to start con"erting the data# Con"ersion is done by using what the AC. calls a stream# We open the stream passing descriptions o% the source and destination %ormats and then as' the stream to con"ert them#

Copyright 4 Nigel Thompson 5997

6age 7

2n the case we8ll loo' at here the con"ersion is done synchronously and may ta'e &uite some time i% the CO !C algorithm is comple1# $ome CO !Cs can wor' asynchronously noti%ying you as things progress "ia a message to a window/ a call to a callbac' %unction or setting an e"ent# The code here :ust gets the :ob done with the least %uss 3 but you do get to wait until it8s complete# There is one other important point# As you8ll see/ when we open the con"ersion streams we speci%y the AC.J$T=!A.O6!N0JNON=!A;T2.! %lag# This is "ery important# 2% you omit this %lag then some dri"ers +%or e1ample the True$peech dri"er- will report error 55A +not possible-# This error is telling you that the con"ersion you as'ed %or cannot be done in real time# This isn8t an issue in my sample but it would be i% you were trying to con"ert a lot o% data at the same time you were playing it# $o let8s loo' now at the %irst con"ersion step which con"erts the source %ormat to the intermediate %ormat<

///////////////////////////////////////////////////////////////////////////// // convert the source wave to the ?CM 'ormat supported ,y the COD7C // we use any driver that can do the ?CM to ?CM conversion .ACM8: 7AM hstr " ;944& mmr " acm8treamOpen$1hstr;944- // any driver 1w'8rc- // source 'ormat pw'?CM- // destination 'ormat ;944- // no 'ilter ;944- // no call,acL *- // instance data $not used% ACM<8: 7AMO?7;3<;O; 7A4:/M7%& // 'lags i' $mmr% = print'$(3ailed to open a stream to do ?CM to ?CM conversion5n(%& e2it$J%& > // allocate a ,u''er 'or the result o' the conversion. DWO D dw8rc@ytes " dw8rc8amples G w'8rc.w@its?er8ample / 0& DWO D dwDstJ8amples " dw8rc8amples G pw'?CMF>n8amples?er8ec / w'8rc.n8amples?er8ec& DWO D dwDstJ@ytes " dwDstJ8amples G pw'?CMF>w@its?er8ample / 0& @B:7G pDstJData " new @B:7 MdwDstJ@ytesN& // 'ill in the conversion in'o ACM8: 7AM.7AD7 strhdr& memset$1strhdr- *- siCeo'$strhdr%%& strhdr.c,8truct " siCeo'$strhdr%& strhdr.p,8rc " p8rcData& // the source data to convert strhdr.c,8rc4ength " dw8rc@ytes& strhdr.p,Dst " pDstJData& strhdr.c,Dst4ength " dwDstJ@ytes& // prep the header mmr " acm8tream?repare.eader$hstr- 1strhdr- *%& // convert the data print'$(Converting to intermediate ?CM 'ormat...5n(%& mmr " acm8treamConvert$hstr- 1strhdr- *%& i' $mmr% =

Copyright 4 Nigel Thompson 5997

6age G

print'$(3ailed to do ?CM to ?CM conversion5n(%& e2it$J%& > print'$(Converted OA5n(%& // close the stream acm8treamClose$hstr- *%& When the stream is opened the second parameter is set to NB;;/ indicating that we will accept any dri"er to per%orm this con"ersion# The only comple1ity is computing how much bu%%er space we8ll need %or the output data# $ince a 6C. to 6C. con"ersion in"ol"es no compression or decompression the computation is straight %orward# 9ou might note the call to acm%treamPrepare,eader which actually is a con"enience %or the dri"er and allows it to loc' the memory be%ore con"ersion begins# The %inal step is to con"ert the intermediate %ormat to the %inal compressed %ormat<

//////////////////////////////////////////////////////////////////////////////// /// // convert the intermediate ?CM 'ormat to the 'inal 'ormat // open the driver .ACMD /!7 had " ;944& mmr " acmDriverOpen$1had- hadid- *%& i' $mmr% = print'$(3ailed to open driver5n(%& e2it$J%& > // open the conversion stream // ;ote the use o' the ACM<8: 7AMO?7;3<;O; 7A4:/M7 'lag. Without this // some so'tware compressors will report error KJ+ F not possi,le mmr " acm8treamOpen$1hstrhad- // driver handle pw'?CM- // source 'ormat pw'Drv- // destination 'ormat ;944- // no 'ilter ;944- // no call,acL *- // instance data $not used% ACM<8: 7AMO?7;3<;O; 7A4:/M7%& // 'lags i' $mmr% = print'$(3ailed to open a stream to do ?CM to driver 'ormat conversion5n(%& e2it$J%& > // allocate a ,u''er 'or the result o' the conversion. // compute the output ,u''er siCe ,ased on the average ,yte rate // and add a ,it 'or randomness // the /MA<AD?CM driver 'ails the conversion without this e2tra space DWO D dwDst+@ytes " pw'DrvF>nAvg@ytes?er8ec G dwDstJ8amples / pw'?CMF>n8amples?er8ec& dwDst+@ytes " dwDst+@ytes G Q / +& // add a little room

Copyright 4 Nigel Thompson 5997

6age 9

@B:7G pDst+Data " new @B:7 MdwDst+@ytesN& // 'ill in the conversion in'o ACM8: 7AM.7AD7 strhdr+& memset$1strhdr+- *- siCeo'$strhdr+%%& strhdr+.c,8truct " siCeo'$strhdr+%& strhdr+.p,8rc " pDstJData& // the source data to convert strhdr+.c,8rc4ength " dwDstJ@ytes& strhdr+.p,Dst " pDst+Data& strhdr+.c,Dst4ength " dwDst+@ytes& // prep the header mmr " acm8tream?repare.eader$hstr- 1strhdr+- *%& // convert the data print'$(Converting to 'inal 'ormat...5n(%& mmr " acm8treamConvert$hstr- 1strhdr+- *%& i' $mmr% = print'$(3ailed to do ?CM to driver 'ormat conversion5n(%& e2it$J%& > print'$(Converted OA5n(%& // close the stream and driver mmr " acm8treamClose$hstr- *%& mmr " acmDriverClose$had- *%& This is "ery similar to the 6C. to 6C. con"ersion but in this case we supply the handle to the dri"er we want to use when we open the stream# Actually we could supply NB;; here too since we already ascertained that the dri"er e1ists/ but supplying the handle a"oids the system wasting time %inding the dri"er %or us# Computing the bu%%er siCe %or the compressed data is a little tric' and re&uires some slight guesswor'# The nAvg-ytesPer%ec %ield o% the WAVEFO !A"E# structure indicates the a"erage rate at which bytes are read during playbac'# We can use this to estimate how much data we need to store the compressed wa"e# $ome dri"ers gi"e data that is truly a"erage and not the worst case so 2 chose to add 5*K more to the bu%%er which wor's well in practice e"en i% it is a little waste%ul# Once the con"ersion is complete the cbDst.engthUsed %ield o% the AC!%" EA!,EADE structure contains the actual number o% bytes used in the bu%%er and 2 used this to compute the compression ratio<

// show the conversion stats print'$(8ource wave had )lu ,ytes5n(- dw8rc@ytes%& print'$(Converted wave has )lu ,ytes5n(- strhdr+.c,Dst4ength9sed%& print'$(Compression ratio is )'5n(- $dou,le% dw8rc@ytes / $dou,le% strhdr+.c,Dst4ength9sed%&

%ummary

Copyright 4 Nigel Thompson 5997

6age 5*

Compressing wa"e%orm data using Windows8 built,in CO !Cs is easy to do and results in data which occupies less dis' space and ta'es less time to transmit# 2% you ha"e a proprietary compression %ormat you can create you own CO !C to install and use it in the same way 28"e shown here# As usual/ 28m happy to answer &uestions regarding this article# 2 can be contacted by email< nigel,tLmsn#com

Copyright 4 Nigel Thompson 5997

6age 55

You might also like