Nothing Special   »   [go: up one dir, main page]

Using Codecs To Compress Wave Audio

Download as doc, pdf, or txt
Download as doc, pdf, or txt
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