1
0

main.cpp 220 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222222322242225222622272228222922302231223222332234223522362237223822392240224122422243224422452246224722482249225022512252225322542255225622572258225922602261226222632264226522662267226822692270227122722273227422752276227722782279228022812282228322842285228622872288228922902291229222932294229522962297229822992300230123022303230423052306230723082309231023112312231323142315231623172318231923202321232223232324232523262327232823292330233123322333233423352336233723382339234023412342234323442345234623472348234923502351235223532354235523562357235823592360236123622363236423652366236723682369237023712372237323742375237623772378237923802381238223832384238523862387238823892390239123922393239423952396239723982399240024012402240324042405240624072408240924102411241224132414241524162417241824192420242124222423242424252426242724282429243024312432243324342435243624372438243924402441244224432444244524462447244824492450245124522453245424552456245724582459246024612462246324642465246624672468246924702471247224732474247524762477247824792480248124822483248424852486248724882489249024912492249324942495249624972498249925002501250225032504250525062507250825092510251125122513251425152516251725182519252025212522252325242525252625272528252925302531253225332534253525362537253825392540254125422543254425452546254725482549255025512552255325542555255625572558255925602561256225632564256525662567256825692570257125722573257425752576257725782579258025812582258325842585258625872588258925902591259225932594259525962597259825992600260126022603260426052606260726082609261026112612261326142615261626172618261926202621262226232624262526262627262826292630263126322633263426352636263726382639264026412642264326442645264626472648264926502651265226532654265526562657265826592660266126622663266426652666266726682669267026712672267326742675267626772678267926802681268226832684268526862687268826892690269126922693269426952696269726982699270027012702270327042705270627072708270927102711271227132714271527162717271827192720272127222723272427252726272727282729273027312732273327342735273627372738273927402741274227432744274527462747274827492750275127522753275427552756275727582759276027612762276327642765276627672768276927702771277227732774277527762777277827792780278127822783278427852786278727882789279027912792279327942795279627972798279928002801280228032804280528062807280828092810281128122813281428152816281728182819282028212822282328242825282628272828282928302831283228332834283528362837283828392840284128422843284428452846284728482849285028512852285328542855285628572858285928602861286228632864286528662867286828692870287128722873287428752876287728782879288028812882288328842885288628872888288928902891289228932894289528962897289828992900290129022903290429052906290729082909291029112912291329142915291629172918291929202921292229232924292529262927292829292930293129322933293429352936293729382939294029412942294329442945294629472948294929502951295229532954295529562957295829592960296129622963296429652966296729682969297029712972297329742975297629772978297929802981298229832984298529862987298829892990299129922993299429952996299729982999300030013002300330043005300630073008300930103011301230133014301530163017301830193020302130223023302430253026302730283029303030313032303330343035303630373038303930403041304230433044304530463047304830493050305130523053305430553056305730583059306030613062306330643065306630673068306930703071307230733074307530763077307830793080308130823083308430853086308730883089309030913092309330943095309630973098309931003101310231033104310531063107310831093110311131123113311431153116311731183119312031213122312331243125312631273128312931303131313231333134313531363137313831393140314131423143314431453146314731483149315031513152315331543155315631573158315931603161316231633164316531663167316831693170317131723173317431753176317731783179318031813182318331843185318631873188318931903191319231933194319531963197319831993200320132023203320432053206320732083209321032113212321332143215321632173218321932203221322232233224322532263227322832293230323132323233323432353236323732383239324032413242324332443245324632473248324932503251325232533254325532563257325832593260326132623263326432653266326732683269327032713272327332743275327632773278327932803281328232833284328532863287328832893290329132923293329432953296329732983299330033013302330333043305330633073308330933103311331233133314331533163317331833193320332133223323332433253326332733283329333033313332333333343335333633373338333933403341334233433344334533463347334833493350335133523353335433553356335733583359336033613362336333643365336633673368336933703371337233733374337533763377337833793380338133823383338433853386338733883389339033913392339333943395339633973398339934003401340234033404340534063407340834093410341134123413341434153416341734183419342034213422342334243425342634273428342934303431343234333434343534363437343834393440344134423443344434453446344734483449345034513452345334543455345634573458345934603461346234633464346534663467346834693470347134723473347434753476347734783479348034813482348334843485348634873488348934903491349234933494349534963497349834993500350135023503350435053506350735083509351035113512351335143515351635173518351935203521352235233524352535263527352835293530353135323533353435353536353735383539354035413542354335443545354635473548354935503551355235533554355535563557355835593560356135623563356435653566356735683569357035713572357335743575357635773578357935803581358235833584358535863587358835893590359135923593359435953596359735983599360036013602360336043605360636073608360936103611361236133614361536163617361836193620362136223623362436253626362736283629363036313632363336343635363636373638363936403641364236433644364536463647364836493650365136523653365436553656365736583659366036613662366336643665366636673668366936703671367236733674367536763677367836793680368136823683368436853686368736883689369036913692369336943695369636973698369937003701370237033704370537063707370837093710371137123713371437153716371737183719372037213722372337243725372637273728372937303731373237333734373537363737373837393740374137423743374437453746374737483749375037513752375337543755375637573758375937603761376237633764376537663767376837693770377137723773377437753776377737783779378037813782378337843785378637873788378937903791379237933794379537963797379837993800380138023803380438053806380738083809381038113812381338143815381638173818381938203821382238233824382538263827382838293830383138323833383438353836383738383839384038413842384338443845384638473848384938503851385238533854385538563857385838593860386138623863386438653866386738683869387038713872387338743875387638773878387938803881388238833884388538863887388838893890389138923893389438953896389738983899390039013902390339043905390639073908390939103911391239133914391539163917391839193920392139223923392439253926392739283929393039313932393339343935393639373938393939403941394239433944394539463947394839493950395139523953395439553956395739583959396039613962396339643965396639673968396939703971397239733974397539763977397839793980398139823983398439853986398739883989399039913992399339943995399639973998399940004001400240034004400540064007400840094010401140124013401440154016401740184019402040214022402340244025402640274028402940304031403240334034403540364037403840394040404140424043404440454046404740484049405040514052405340544055405640574058405940604061406240634064406540664067406840694070407140724073407440754076407740784079408040814082408340844085408640874088408940904091409240934094409540964097409840994100410141024103410441054106410741084109411041114112411341144115411641174118411941204121412241234124412541264127412841294130413141324133413441354136413741384139414041414142414341444145414641474148414941504151415241534154415541564157415841594160416141624163416441654166416741684169417041714172417341744175417641774178417941804181418241834184418541864187418841894190419141924193419441954196419741984199420042014202420342044205420642074208420942104211421242134214421542164217421842194220422142224223422442254226422742284229423042314232423342344235423642374238423942404241424242434244424542464247424842494250425142524253425442554256425742584259426042614262426342644265426642674268426942704271427242734274427542764277427842794280428142824283428442854286428742884289429042914292429342944295429642974298429943004301430243034304430543064307430843094310431143124313431443154316431743184319432043214322432343244325432643274328432943304331433243334334433543364337433843394340434143424343434443454346434743484349435043514352435343544355435643574358435943604361436243634364436543664367436843694370437143724373437443754376437743784379438043814382438343844385438643874388438943904391439243934394439543964397439843994400440144024403440444054406440744084409441044114412441344144415441644174418441944204421442244234424442544264427442844294430443144324433443444354436443744384439444044414442444344444445444644474448444944504451445244534454445544564457445844594460446144624463446444654466446744684469447044714472447344744475447644774478447944804481448244834484448544864487448844894490449144924493449444954496449744984499450045014502450345044505450645074508450945104511451245134514451545164517451845194520452145224523452445254526452745284529453045314532453345344535453645374538453945404541454245434544454545464547454845494550455145524553455445554556455745584559456045614562456345644565456645674568456945704571457245734574457545764577457845794580458145824583458445854586458745884589459045914592459345944595459645974598459946004601460246034604460546064607460846094610461146124613461446154616461746184619462046214622462346244625462646274628462946304631463246334634463546364637463846394640464146424643464446454646464746484649465046514652465346544655465646574658465946604661466246634664466546664667466846694670467146724673467446754676467746784679468046814682468346844685468646874688468946904691469246934694469546964697469846994700470147024703470447054706470747084709471047114712471347144715471647174718471947204721472247234724472547264727472847294730473147324733473447354736473747384739474047414742474347444745474647474748474947504751475247534754475547564757475847594760476147624763476447654766476747684769477047714772477347744775477647774778477947804781478247834784478547864787478847894790479147924793479447954796479747984799480048014802480348044805480648074808480948104811481248134814481548164817481848194820482148224823482448254826482748284829483048314832483348344835483648374838483948404841484248434844484548464847484848494850485148524853485448554856485748584859486048614862486348644865486648674868486948704871487248734874487548764877487848794880488148824883488448854886488748884889489048914892489348944895489648974898489949004901490249034904490549064907490849094910491149124913491449154916491749184919492049214922492349244925492649274928492949304931493249334934493549364937493849394940494149424943494449454946494749484949495049514952495349544955495649574958495949604961496249634964496549664967496849694970497149724973497449754976497749784979498049814982498349844985498649874988498949904991499249934994499549964997499849995000500150025003500450055006500750085009501050115012501350145015501650175018501950205021502250235024502550265027502850295030503150325033503450355036503750385039504050415042504350445045504650475048504950505051505250535054505550565057505850595060506150625063506450655066506750685069507050715072507350745075507650775078507950805081508250835084508550865087508850895090509150925093509450955096509750985099510051015102510351045105510651075108510951105111511251135114511551165117511851195120512151225123512451255126512751285129513051315132513351345135513651375138513951405141514251435144514551465147514851495150515151525153515451555156515751585159516051615162516351645165516651675168516951705171517251735174517551765177517851795180518151825183518451855186518751885189519051915192519351945195519651975198519952005201520252035204520552065207520852095210521152125213521452155216521752185219522052215222522352245225522652275228522952305231523252335234523552365237523852395240524152425243524452455246524752485249525052515252525352545255525652575258525952605261526252635264526552665267526852695270527152725273527452755276527752785279528052815282528352845285528652875288528952905291529252935294529552965297529852995300530153025303530453055306530753085309531053115312531353145315531653175318531953205321532253235324532553265327532853295330533153325333533453355336533753385339534053415342534353445345534653475348534953505351535253535354535553565357535853595360536153625363536453655366536753685369537053715372537353745375537653775378537953805381538253835384538553865387538853895390539153925393539453955396539753985399540054015402540354045405540654075408540954105411541254135414541554165417541854195420542154225423542454255426542754285429543054315432543354345435543654375438543954405441544254435444544554465447544854495450545154525453545454555456545754585459546054615462546354645465546654675468546954705471547254735474547554765477547854795480548154825483548454855486548754885489549054915492549354945495549654975498549955005501550255035504550555065507550855095510551155125513551455155516551755185519552055215522552355245525552655275528552955305531553255335534553555365537553855395540554155425543554455455546554755485549555055515552555355545555555655575558555955605561556255635564556555665567556855695570557155725573557455755576557755785579558055815582558355845585558655875588558955905591559255935594559555965597559855995600560156025603560456055606560756085609561056115612561356145615561656175618561956205621562256235624562556265627562856295630563156325633563456355636563756385639564056415642564356445645564656475648564956505651565256535654565556565657565856595660566156625663566456655666566756685669567056715672567356745675567656775678567956805681568256835684568556865687568856895690569156925693569456955696569756985699570057015702570357045705570657075708570957105711571257135714571557165717571857195720572157225723572457255726572757285729573057315732573357345735573657375738573957405741574257435744574557465747574857495750575157525753575457555756575757585759576057615762576357645765576657675768576957705771577257735774577557765777577857795780578157825783578457855786578757885789579057915792579357945795579657975798579958005801580258035804
  1. // These are disabled for now they have unknown issues.
  2. //#define USE_OGG
  3. //#define CAPTURE_TESTING
  4. // TODO / BE NICE FOR FUTURE VERSIONS
  5. // 1) Fix capture issues on Vista / Windows 7
  6. // 2) Allow metadata to be specified from file
  7. // 3) Move over to using enc_lame (and ui changes for it) [partial]
  8. #define APP_Name "Shoutcast Source"
  9. #define APP_Version "2.4.2"
  10. #define APP_VersionW L"2.4.2"
  11. #define APP_Build "449"
  12. #include <windows.h>
  13. #include <commctrl.h>
  14. #include <stdio.h>
  15. #include <shlobj.h>
  16. #include <shellapi.h>
  17. #include <shlwapi.h>
  18. #include <commdlg.h>
  19. #include <math.h>
  20. #include <mmdeviceapi.h>
  21. #include <audioclient.h>
  22. #include <endpointvolume.h>
  23. #include <functiondiscoverykeys.h>
  24. #ifdef CAPTURE_TESTING
  25. #include "Wasapi/WASAPICapture.h"
  26. #endif
  27. #include "resource/resource.h"
  28. #include "sc2srclib/include/shoutcast_output.h"
  29. #include "sc2srclib/encoders/c_encoder_mp3dll.h"
  30. #include "sc2srclib/encoders/c_encoder_nsv.h"
  31. #include "sc2srclib/encoders/c_encoder_fhgaac.h"
  32. #include "sc2srclib/encoders/c_encoder_aacp.h"
  33. #ifdef USE_OGG
  34. #include "sc2srclib/Encoders/c_encoder_ogg.h"
  35. #endif
  36. // allows us to compile with the Wasabi sdk without having to change things
  37. //#define __WASABI_TYPES_H
  38. //#define _GUID_H
  39. //typedef unsigned long ARGB32;
  40. //static const GUID INVALID_GUID = { 0, 0, 0, {0, 0, 0, 0, 0, 0, 0, 0} };
  41. #include "api.h"
  42. #include "include/c_wavein.h"
  43. #include "crossfader/c_crossfader.h"
  44. #include <winamp/wa_ipc.h>
  45. #include <winamp/dsp.h>
  46. #include "nu/servicebuilder.h"
  47. #include "utils.h"
  48. #ifdef CAPTURE_TESTING
  49. #include "wasapi/player.h"
  50. #endif
  51. #include <strsafe.h>
  52. #define NUM_OUTPUTS 5
  53. #define NUM_ENCODERS NUM_OUTPUTS
  54. #define NUM_BUFFERS 3
  55. #define MAX_TABWNDS 4
  56. #define MAX_COLS 6
  57. #define MAX_CELLS 12
  58. #define MAX_INWNDS 2
  59. #define MAX_OUTWNDS 6
  60. #define SYSTRAY_BASE_ICON 1024
  61. #define SYSTRAY_ICY_ICON 1
  62. #define SYSTRAY_BASE_MSG WM_USER
  63. #define SYSTRAY_MAXIMIZE_MSG 27
  64. #define DEFAULT_INPUTDEVICE 0 // winamp
  65. #define DOWNLOAD_URL L"http://www.shoutcast.com/BroadcastNow"
  66. // 404, change to one of these?
  67. // #define DOWNLOAD_URL L"http://wiki.shoutcast.com/wiki/Source_DSP_Plug-in"
  68. // #define DOWNLOAD_URL L"http://www.shoutcast.com"
  69. char sourceVersion[64] = {APP_Version "." APP_Build};
  70. static char szDescription[256];
  71. static char szDescription2[256];
  72. static wchar_t szDescription2W[256];
  73. #ifdef CAPTURE_TESTING
  74. static Player *pPlayer = NULL;
  75. //
  76. // The Player object calls the methods in this class to
  77. // notify the application when certain audio events occur.
  78. //
  79. class CPlayerCallbacks : public PlayerCallbacks
  80. {
  81. // Notification callback for volume change. Typically, the user
  82. // adjusts the volume through the SndVol.exe application.
  83. void VolumeChangeCallback(float volume, BOOL mute)
  84. {
  85. /*EnableWindowDlgItem(g_hDlg, IDC_SLIDER_VOLUME, TRUE);
  86. SetWindowText(GetDlgItem(g_hDlg, IDC_STATIC_MUTE),
  87. (mute == TRUE) ? L"Mute" : L"");
  88. PostMessage(GetDlgItem(g_hDlg, IDC_SLIDER_VOLUME),
  89. TBM_SETPOS, TRUE, LPARAM(volume*MAX_VOLUME_LEVEL));*/
  90. };
  91. // Notification callback for when stream stops playing unexpectedly
  92. // (typically, because the player reached the end of a wave file).
  93. void PlayerStopCallback(void)
  94. {
  95. /*SetActiveWindow(g_hDlg);
  96. PostMessage(GetDlgItem(g_hDlg, IDC_BUTTON_STOP), BM_CLICK, 0, 0);*/
  97. };
  98. // Notification callback for when the endpoint capture device is
  99. // disconnected (for example, the user pulls out the microphone plug).
  100. void CaptureDisconnectCallback(void)
  101. {
  102. /*SetWindowText(GetDlgItem(g_hDlg, IDC_STATIC_LASTACTION),
  103. L"Capture device disconnected!");
  104. SendMessage(GetDlgItem(g_hDlg, IDC_COMBO_CAPTUREDEVICE), CB_RESETCONTENT, 0, 0);*/
  105. };
  106. // Notification callback for when the endpoint rendering device is
  107. // disconnected (for example, the user pulls out the headphones plug).
  108. void RenderDisconnectCallback(void)
  109. {
  110. /*SetWindowText(GetDlgItem(g_hDlg, IDC_STATIC_LASTACTION),
  111. L"Playback device disconnected!");
  112. EnableWindowDlgItem(g_hDlg, IDC_SLIDER_VOLUME, FALSE);
  113. SetWindowTextW(GetDlgItem(g_hDlg, IDC_STATIC_MUTE), L"Disconnected");
  114. SendMessage(GetDlgItem(g_hDlg, IDC_COMBO_RENDERDEVICE), CB_RESETCONTENT, 0, 0);
  115. SendMessage(GetDlgItem(g_hDlg, IDC_SLIDER_VOLUME), TBM_SETPOS, TRUE, 0);*/
  116. };
  117. };
  118. static CPlayerCallbacks *pCallbacks = NULL;
  119. #endif
  120. // this is used to help determine if we're running on an older
  121. // version of Winamp where jnetlib has issues with the re-use
  122. // of connection handles when the connection previously failed
  123. int iscompatibility = 0;
  124. // used for the about page link so we don't cause win2k issues
  125. int isthemethere = 0;
  126. // Wasabi based services for localisation support
  127. api_service *WASABI_API_SVC = 0;
  128. api_config *AGAVE_API_CONFIG = 0;
  129. api_language *WASABI_API_LNG = 0;
  130. api_queue *WASABI_API_QUEUEMGR = 0;
  131. api_albumart *AGAVE_API_ALBUMART = 0;
  132. api_memmgr *WASABI_API_MEMMGR = 0;
  133. api_explorerfindfile* WASABI_API_EXPLORERFINDFILE = 0;
  134. api_downloadManager *WAC_API_DOWNLOADMANAGER = 0;
  135. // these two must be declared as they're used by the language api's
  136. // when the system is comparing/loading the different resources
  137. HINSTANCE WASABI_API_LNG_HINST = 0,
  138. WASABI_API_ORIG_HINST = 0;
  139. HFONT boldFont = 0, normalFont = 0;
  140. HICON icy = 0, wa_icy = 0;
  141. static HHOOK nowPlayingHook,
  142. nowPlayingHook2;
  143. static LPARAM nowPlayingID = -1;
  144. // just using these to track the paused and playing states
  145. int was_paused = 0,
  146. was_playing = 0;
  147. DWORD play_duration = 0,
  148. play_diff = 0;
  149. int isplaying = -1, ptt_load = 0;
  150. static wchar_t lastFile[MAX_PATH];
  151. int lastFilterIndex = 4;
  152. static int lastSec[NUM_OUTPUTS],
  153. lastMode[NUM_OUTPUTS] = {-1, -1, -1, -1, -1},
  154. lastEnable[NUM_OUTPUTS];
  155. static HWND buttonWnd[ NUM_OUTPUTS ];
  156. static HWND tabWnd;
  157. static HWND outTabWnd;
  158. static HWND updateWnd;
  159. static ARGB32 *playingImage;
  160. static ARGB32 *streamImage[NUM_OUTPUTS] = {(ARGB32 *)-1, (ARGB32 *)-1, (ARGB32 *)-1, (ARGB32 *)-1, (ARGB32 *)-1};
  161. static int playingImage_w, playingImage_h, playingLength, playingType;
  162. static int streamLength[NUM_OUTPUTS];
  163. static bool secChanged[NUM_OUTPUTS];
  164. void Config(struct winampDSPModule *this_mod);
  165. int Init(struct winampDSPModule *this_mod);
  166. int ModifySamples(struct winampDSPModule *this_mod, short int *samples, int numsamples, int bps, int nch, int srate);
  167. void Quit(struct winampDSPModule *this_mod);
  168. int secureFunc(int key){
  169. int res = key * (unsigned long)1103515245;
  170. res += (unsigned long)13293;
  171. res &= (unsigned long)0x7FFFFFFF;
  172. res ^= key;
  173. return res;
  174. }
  175. winampDSPModule *getModule(int which);
  176. winampDSPModule module = {
  177. "nullsoft(dsp_sc.dll)",
  178. NULL,
  179. NULL,
  180. Config,
  181. Init,
  182. ModifySamples,
  183. Quit,
  184. NULL
  185. };
  186. winampDSPHeader header = {
  187. DSP_HDRVER+1,
  188. "Nullsoft " APP_Name " DSP " APP_Version,
  189. getModule,
  190. secureFunc
  191. };
  192. static ARGB32 * writeImg(const ARGB32 *data, int w, int h, int *length, const wchar_t *ext) {
  193. if (!ext || ext && !*ext) return NULL;
  194. if (*ext == L'.') ext++;
  195. FOURCC imgwrite = svc_imageWriter::getServiceType();
  196. int n = WASABI_API_SVC->service_getNumServices(imgwrite);
  197. for (int i=0; i<n; i++) {
  198. waServiceFactory *sf = WASABI_API_SVC->service_enumService(imgwrite,i);
  199. if (sf) {
  200. svc_imageWriter * l = (svc_imageWriter*)sf->getInterface();
  201. if (l) {
  202. if (wcsstr(l->getExtensions(),ext)) {
  203. void* ret = l->convert(data, 32, w, h, length);
  204. sf->releaseInterface(l);
  205. return (ARGB32 *)ret;
  206. }
  207. sf->releaseInterface(l);
  208. }
  209. }
  210. }
  211. return NULL;
  212. }
  213. HICON GetICYIcon(bool winamp = false) {
  214. if (!winamp) {
  215. if (!icy) {
  216. icy = (HICON)LoadImage(WASABI_API_ORIG_HINST?WASABI_API_ORIG_HINST:module.hDllInstance,
  217. MAKEINTRESOURCE(IDI_ICY), IMAGE_ICON, 0, 0,
  218. LR_SHARED | LR_LOADTRANSPARENT | LR_CREATEDIBSECTION);
  219. }
  220. return icy;
  221. } else {
  222. if (!wa_icy) {
  223. wa_icy = (HICON)LoadImage(GetModuleHandle("winamp.exe"),
  224. MAKEINTRESOURCE(102), IMAGE_ICON, 0, 0,
  225. LR_SHARED | LR_LOADTRANSPARENT | LR_CREATEDIBSECTION);
  226. }
  227. return (wa_icy ? wa_icy : icy);
  228. }
  229. }
  230. BOOL InitLocalisation(HWND winamp) {
  231. // if this is valid then we should be running on Winamp 5.5+ so try to get the localisation api
  232. if (IsWindow(winamp)) {
  233. iscompatibility = 1; ////// SendMessage( winamp, WM_WA_IPC, 0, IPC_IS_COMPATIBILITY_ENABLED );
  234. isthemethere = !SendMessage(winamp, WM_WA_IPC, IPC_ISWINTHEMEPRESENT, IPC_USE_UXTHEME_FUNC);
  235. if (!WASABI_API_LNG_HINST) {
  236. // loader so that we can get the localisation service api for use
  237. WASABI_API_SVC = (api_service*)SendMessage(winamp, WM_WA_IPC, 0, IPC_GET_API_SERVICE);
  238. if (WASABI_API_SVC == (api_service*)1) {
  239. WASABI_API_SVC = NULL;
  240. return FALSE;
  241. }
  242. // initialise all of the wasabi based services
  243. ServiceBuild(WASABI_API_SVC, AGAVE_API_CONFIG, AgaveConfigGUID);
  244. ServiceBuild(WASABI_API_SVC, WASABI_API_LNG, languageApiGUID);
  245. ServiceBuild(WASABI_API_SVC, WASABI_API_MEMMGR, memMgrApiServiceGuid);
  246. ServiceBuild(WASABI_API_SVC, AGAVE_API_ALBUMART, albumArtGUID);
  247. ServiceBuild(WASABI_API_SVC, WASABI_API_QUEUEMGR, QueueManagerApiGUID);
  248. ServiceBuild(WASABI_API_SVC, WASABI_API_EXPLORERFINDFILE, ExplorerFindFileApiGUID);
  249. ServiceBuild(WASABI_API_SVC, WAC_API_DOWNLOADMANAGER, DownloadManagerGUID);
  250. // need to have this initialised before we try to do anything with localisation features
  251. WASABI_API_START_LANG(GetMyInstance(), DspShoutcastLangGUID);
  252. // do this here so if there is no localisation support then the module names go to defaults
  253. if (!szDescription[0]) {
  254. StringCchPrintfA(szDescription, ARRAYSIZE(szDescription), LocalisedStringA(IDS_PLUGIN_NAME, NULL, 0), APP_Version);
  255. header.description = szDescription;
  256. }
  257. if (!szDescription2[0]) {
  258. module.description = LocalisedStringA(IDS_MODULE_NAME, szDescription2, 256);
  259. LocalisedString(IDS_MODULE_NAME, szDescription2W, 256);
  260. }
  261. }
  262. return TRUE;
  263. }
  264. return FALSE;
  265. }
  266. #ifdef __cplusplus
  267. extern "C" {
  268. #endif
  269. __declspec(dllexport) winampDSPHeader *winampDSPGetHeader2(HWND hwndParent) {
  270. if (InitLocalisation(hwndParent)) {
  271. return &header;
  272. }
  273. MessageBoxA(module.hwndParent,
  274. "You are attempting to use the " APP_Name " plug-in in an\n"
  275. "unsupported version of Winamp or in a non-Winamp install or via a\n"
  276. "DSP stacker which does not implement the Winamp 5.5+ DSP api.\n\n"
  277. "To work this plug-in requires Winamp 5.5 and higher (the most current\n"
  278. "release is recommended) or for the non-Winamp install or DSP stacker\n"
  279. "to be updated to support the required Winamp api's the plug-in uses.",
  280. "Nullsoft " APP_Name, MB_ICONEXCLAMATION|MB_APPLMODAL);
  281. return 0;
  282. }
  283. __declspec(dllexport) int winampUninstallPlugin(HINSTANCE hDllInst, HWND hwndDlg, int param) {
  284. // this isn't ideal but it ensures that we show a localised version of the message
  285. // if not it'll make sure that we're using the plug-in dll's internal resources
  286. // though for ease of code handling we have to fill in some of the dsp structures
  287. // as the plug-in has effectively been unloaded at this stage for the uninstall.
  288. HWND winamp = GetWinampHWND(0);
  289. module.hDllInstance = hDllInst;
  290. module.hwndParent = winamp;
  291. InitLocalisation(winamp);
  292. wchar_t title[256] = {0};
  293. StringCchPrintfW(title, ARRAYSIZE(title), LocalisedString(IDS_PLUGIN_NAME, NULL, 0), APP_Version);
  294. // prompt to remove the settings files (defaults to no just incase)
  295. if (MessageBoxW(hwndDlg, LocalisedString(IDS_PLUGIN_UNINSTALL, NULL, 0), title, MB_YESNO|MB_DEFBUTTON2) == IDYES) {
  296. DeleteFile(GetSCIniFile(winamp));
  297. }
  298. return DSP_PLUGIN_UNINSTALL_NOW;
  299. }
  300. #ifdef __cplusplus
  301. }
  302. #endif
  303. winampDSPModule *getModule(int which) {
  304. if (which == 0) return &module;
  305. return NULL;
  306. }
  307. // Client's proprietary event-context GUID
  308. //extern GUID g_guidMyContext;
  309. // Maximum volume level on trackbar
  310. #define MAX_VOL 100
  311. #define SAFE_RELEASE(what) \
  312. if ((what) != NULL) \
  313. { (what)->Release(); (what) = NULL; }
  314. //GUID g_guidMyContext = GUID_NULL;
  315. static IAudioStreamVolume *g_pStreamVol = NULL;
  316. static IAudioEndpointVolume *g_pEndptVol = NULL;
  317. static IAudioClient *g_pAudioClient = NULL;
  318. static IAudioCaptureClient *g_pCaptureClient = NULL;
  319. /*#define EXIT_ON_ERROR(hr) \
  320. if (FAILED(hr)) { goto Exit; }
  321. #define ERROR_CANCEL(hr) \
  322. if (FAILED(hr)) { \
  323. MessageBox(hDlg, TEXT("The program will exit."), \
  324. TEXT("Fatal error"), MB_OK); \
  325. EndDialog(hDlg, TRUE); return TRUE; }*/
  326. HANDLE cf_mutex = NULL;
  327. C_CROSSFADER *Crossfader = NULL;
  328. int CrossfadeLen = 5000;
  329. unsigned int Input_Device_ID=0;
  330. int Restore_PTT = 0;
  331. unsigned int numInputs=0;
  332. char updateStr[16] = {0};
  333. typedef struct {
  334. // BladeEnc DLL Version number
  335. BYTE byDLLMajorVersion;
  336. BYTE byDLLMinorVersion;
  337. // BladeEnc Engine Version Number
  338. BYTE byMajorVersion;
  339. BYTE byMinorVersion;
  340. // DLL Release date
  341. BYTE byDay;
  342. BYTE byMonth;
  343. WORD wYear;
  344. // BladeEnc Homepage URL
  345. #define BE_MAX_HOMEPAGE 128
  346. CHAR zHomepage[BE_MAX_HOMEPAGE + 1];
  347. BYTE byAlphaLevel;
  348. BYTE byBetaLevel;
  349. BYTE byMMXEnabled;
  350. BYTE btReserved[125];
  351. } BE_VERSION, *PBE_VERSION;
  352. typedef VOID (*BEVERSION)(PBE_VERSION);
  353. BEVERSION beVersion = NULL;
  354. void *init = NULL;
  355. void *params = NULL;
  356. void *encode = NULL;
  357. void *finish = NULL;
  358. void *lameclose = NULL;
  359. int CALLBACK DialogFunc(HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam);
  360. HINSTANCE instance = NULL;
  361. HINSTANCE libinst = NULL;
  362. HWND hMainDLG = NULL;
  363. RECT mainrect;
  364. HWND inWin = NULL, inWinWa = NULL;
  365. struct T_TABWND {
  366. HWND hWnd;
  367. int id;
  368. int timer_freq;
  369. TCITEMW tcitem;
  370. } wnd[MAX_TABWNDS] = {0},
  371. out_wnd[MAX_OUTWNDS] = {0};
  372. int num_tabwnds = 0,
  373. num_outwnds = 0;
  374. struct T_COL {
  375. LVCOLUMNW lvcol;
  376. LVITEMW lvitem[MAX_CELLS];
  377. int num_cells;
  378. } col[MAX_COLS] = {0};
  379. int num_cols = 0;
  380. struct T_INPUTWND{
  381. HWND hWnd;
  382. int id;
  383. int timer_freq;
  384. } in_wnd[MAX_INWNDS] = {0};
  385. int num_inwnds = 0;
  386. // shoutcast source
  387. struct T_INPUT_CONFIG {
  388. int srate;
  389. int nch;
  390. };
  391. struct MY_T_OUTPUT {
  392. T_OUTPUT_CONFIG Config;
  393. int Encoder; // encoder this config is used by
  394. int Handle; // handle that the encoder understands
  395. int AutoTitle;
  396. int AutoConnect;
  397. int Logging;
  398. int LogCOS;
  399. int NextTitles;
  400. int nextTrackLog;
  401. int nextTrackLogXML;
  402. wchar_t nextTrackPath[MAX_PATH];
  403. int useArt;
  404. int usePlayingArt;
  405. int useStreamArt;
  406. wchar_t stationArtPath[MAX_PATH];
  407. int saveEncoded;
  408. wchar_t saveEncodedPath[MAX_PATH];
  409. } Output[NUM_OUTPUTS] = {0};
  410. SHOUTCAST_OUTPUT Encoder[NUM_ENCODERS];
  411. HANDLE Enc_mutex[NUM_ENCODERS] = {0};
  412. int Enc_LastType[NUM_ENCODERS] = {0};
  413. C_WAVEIN<NUM_BUFFERS, 5120 > Soundcard;
  414. int last_buffer = 0;
  415. int Connection_CurSelPos = 0;
  416. int Encoder_CurSelPos = 0;
  417. int Input_CurSelPos = 3;
  418. int InputDevice = DEFAULT_INPUTDEVICE;
  419. clock_t audiolag = 0;
  420. clock_t lastaudio = 0;
  421. int curtab = 1;
  422. int curouttab = 0;
  423. int lookAhead = 3;
  424. bool skipMetada = false;
  425. bool doNextLookAhead = false;
  426. HANDLE hthread = NULL;
  427. DWORD threadid = 0;
  428. HANDLE hthreadout = NULL;
  429. DWORD threadoutid = 0;
  430. HWND hWinamp = NULL;
  431. int ini_modified = 0;
  432. HANDLE logFiles[NUM_OUTPUTS] = {INVALID_HANDLE_VALUE, INVALID_HANDLE_VALUE, INVALID_HANDLE_VALUE, INVALID_HANDLE_VALUE, INVALID_HANDLE_VALUE};
  433. struct T_VU {
  434. int vu_l;
  435. int vu_r;
  436. int update;
  437. int lastUpdate;
  438. } VU;
  439. int peak_vu_l = -90;
  440. int peak_vu_r = -90;
  441. T_INPUT_CONFIG InputConfig;
  442. int MusVol = 9;
  443. int Mus2Vol = 3;
  444. int MicVol = 9;
  445. int FadeTime = 20;
  446. int MicFadeTime = 10; // mimic old behaviour with a faster fade up/down of the capture device
  447. int devopts = 0;
  448. clock_t FadeStartTime;
  449. clock_t MicFadeStartTime;
  450. int FadeOut = 0;
  451. WNDPROC prevButtonProc = NULL,
  452. prevListViewProc = NULL,
  453. prevHeaderProc = NULL,
  454. prevTabWndProc = NULL,
  455. prevOutTabWndProc = NULL;
  456. int blockmousemove = 0;
  457. T_INPUT_CONFIG LineInputAttribs[]= {
  458. {22050, 1},
  459. {44100, 1},
  460. {22050, 2},
  461. {44100, 2},
  462. };
  463. void AddSystrayIcon(HWND hWnd, UINT uIconId, HICON hIcon, UINT uMsg, LPWSTR lpszToolTip) {
  464. NOTIFYICONDATAW tnid = {0};
  465. tnid.cbSize = sizeof (NOTIFYICONDATAW);
  466. tnid.hWnd = hWnd;
  467. tnid.uID = SYSTRAY_BASE_ICON + uIconId;
  468. tnid.uFlags = NIF_ICON | NIF_TIP | NIF_MESSAGE;
  469. tnid.uCallbackMessage = SYSTRAY_BASE_MSG + uMsg;
  470. tnid.hIcon = hIcon;
  471. wcsncpy(tnid.szTip, lpszToolTip, ARRAYSIZE(tnid.szTip));
  472. Shell_NotifyIconW(NIM_ADD, &tnid);
  473. return;
  474. }
  475. void RemoveSystrayIcon(HWND hWnd, UINT uIconId) {
  476. NOTIFYICONDATAW tnid = {0};
  477. tnid.cbSize = sizeof (NOTIFYICONDATAW);
  478. tnid.hWnd = hWnd;
  479. tnid.uID = SYSTRAY_BASE_ICON + uIconId;
  480. Shell_NotifyIconW(NIM_DELETE, &tnid);
  481. return;
  482. }
  483. void AddTab(int dialog_id, wchar_t *tab_name, HWND hWndParent, DLGPROC DlgProc, int tab_id, int rect_id, int timer_freq) {
  484. RECT r = {0};
  485. T_TABWND *twnd = &wnd[num_tabwnds];
  486. GetWindowRect(GetDlgItem(hWndParent, rect_id), &r);
  487. ScreenToClient(hWndParent, (POINT *) & r);
  488. twnd->id = dialog_id;
  489. twnd->timer_freq = timer_freq;
  490. twnd->hWnd = LocalisedCreateDialog(instance, dialog_id, hWndParent, DlgProc, dialog_id);
  491. ShowWindow(twnd->hWnd, SW_HIDE);
  492. SetWindowPos(twnd->hWnd, NULL, r.left, r.top, 0, 0, SWP_NOZORDER | SWP_NOSIZE);
  493. twnd->tcitem.mask = TCIF_TEXT;
  494. twnd->tcitem.pszText = tab_name;
  495. twnd->tcitem.cchTextMax = wcslen(tab_name);
  496. SendDlgItemMessage(hWndParent, tab_id, TCM_INSERTITEMW, num_tabwnds++, (LPARAM)&twnd->tcitem);
  497. if (IsWindow(twnd->hWnd) && isthemethere) {
  498. SendMessage(module.hwndParent, WM_WA_IPC, (WPARAM)twnd->hWnd, IPC_USE_UXTHEME_FUNC);
  499. }
  500. }
  501. void SetTab(int tabnum, HWND hWndParent, int tab_id) {
  502. NMHDR nmh;
  503. nmh.code = TCN_SELCHANGE;
  504. nmh.hwndFrom = GetDlgItem(hWndParent, tab_id);
  505. nmh.idFrom = tab_id;
  506. curtab = tabnum;
  507. SendMessage(nmh.hwndFrom, TCM_SETCURSEL, curtab, 0);
  508. SendMessage(hWndParent, WM_NOTIFY, tab_id, (LPARAM) & nmh);
  509. }
  510. void AddInTab(int dialog_id, wchar_t *tab_name, HWND hWndParent) {
  511. RECT r = {0};
  512. T_INPUTWND *twnd = &in_wnd[num_inwnds++];
  513. GetWindowRect(GetDlgItem(hWndParent, IDC_PANEL_RECT), &r);
  514. ScreenToClient(hWndParent, (POINT *)&r);
  515. twnd->id = dialog_id;
  516. twnd->timer_freq = 0;
  517. twnd->hWnd = LocalisedCreateDialog(instance, dialog_id, hWndParent, DialogFunc, dialog_id);
  518. ShowWindow(twnd->hWnd, SW_HIDE);
  519. SetWindowPos(twnd->hWnd, NULL, r.left, r.top, 0, 0, SWP_NOZORDER | SWP_NOSIZE);
  520. SendDlgItemMessageW(hWndParent, IDC_INPUTDEVICE, CB_ADDSTRING, 0, (LPARAM)tab_name);
  521. if (IsWindow(twnd->hWnd) && isthemethere) {
  522. SendMessage(module.hwndParent, WM_WA_IPC, (WPARAM)twnd->hWnd, IPC_USE_UXTHEME_FUNC);
  523. }
  524. }
  525. void SetInTab(int tabnum, HWND hWndParent, int combo_id) {
  526. SendDlgItemMessage(hWndParent, combo_id, CB_SETCURSEL, tabnum, 0);
  527. SendMessage(hWndParent, WM_COMMAND, MAKEWPARAM(combo_id, CBN_SELCHANGE), (LPARAM) GetDlgItem(hWndParent, combo_id));
  528. }
  529. void AddOutTab(int dialog_id, wchar_t *tab_name, HWND hWndParent, DLGPROC DlgProc, int tab_id, int rect_id, int timer_freq) {
  530. RECT r = {0};
  531. T_TABWND *twnd = &out_wnd[num_outwnds];
  532. GetWindowRect(GetDlgItem(hWndParent, IDC_PANELRECT_C), &r);
  533. ScreenToClient(hWndParent, (POINT *)&r);
  534. twnd->id = dialog_id;
  535. twnd->timer_freq = 0;
  536. twnd->hWnd = LocalisedCreateDialog(instance, dialog_id, hWndParent, DlgProc, dialog_id);
  537. ShowWindow(twnd->hWnd, SW_HIDE);
  538. SetWindowPos(twnd->hWnd, NULL, r.left, r.top, 0, 0, SWP_NOZORDER | SWP_NOSIZE);
  539. twnd->tcitem.mask = TCIF_TEXT;
  540. twnd->tcitem.pszText = tab_name;
  541. twnd->tcitem.cchTextMax = wcslen(tab_name);
  542. SendDlgItemMessageW(hWndParent, IDC_CONTAB, TCM_INSERTITEMW, num_outwnds++, (LPARAM) & twnd->tcitem);
  543. if (IsWindow(twnd->hWnd) && isthemethere) {
  544. SendMessage(module.hwndParent, WM_WA_IPC, (WPARAM)twnd->hWnd, IPC_USE_UXTHEME_FUNC);
  545. }
  546. }
  547. void SetOutTab(int tabnum, HWND hWndParent, int tab_id) {
  548. NMHDR nmh;
  549. nmh.code = TCN_SELCHANGE;
  550. nmh.hwndFrom = GetDlgItem(hWndParent, tab_id);
  551. nmh.idFrom = tab_id;
  552. curouttab = tabnum;
  553. SendMessage(nmh.hwndFrom, TCM_SETCURSEL, curouttab, 0);
  554. SendMessage(hWndParent, WM_NOTIFY, tab_id, (LPARAM) & nmh);
  555. }
  556. void AddColumn(wchar_t *column_text, HWND listView) {
  557. T_COL *tcol = &col[num_cols];
  558. tcol->lvcol.mask = LVCF_TEXT;
  559. tcol->lvcol.pszText = column_text;
  560. tcol->lvcol.cchTextMax = wcslen(column_text);
  561. SendMessageW(listView, LVM_INSERTCOLUMNW, num_cols++, (LPARAM)&tcol->lvcol);
  562. }
  563. void AddColItem(wchar_t *cell_text, int colnum, HWND hWndParent, int list_id, int pos = -1) {
  564. LVITEMW *tcell = &col[colnum].lvitem[col[colnum].num_cells];
  565. tcell->mask = TVIF_TEXT;
  566. tcell->iItem = pos == -1 ? col[colnum].num_cells++ : pos;
  567. tcell->iSubItem = colnum;
  568. tcell->pszText = cell_text;
  569. tcell->cchTextMax = wcslen(cell_text);
  570. SendDlgItemMessageW(hWndParent, list_id, pos == -1 && colnum == 0 ? LVM_INSERTITEMW : LVM_SETITEMW, 0, (LPARAM)tcell);
  571. }
  572. void __inline interleave_buffer(const short * inLeft, short *outputbuf, const size_t num_samples) {
  573. for (size_t i = 0; i < num_samples; ++i) {
  574. outputbuf[i * 2] = inLeft[i];
  575. outputbuf[i * 2 + 1] = inLeft[i];
  576. }
  577. }
  578. DWORD WINAPI ThreadInput(LPVOID lpParameter) {
  579. do {
  580. // this is needed when doing soundcard capture
  581. if (InputDevice == 1) DialogFunc((HWND) lpParameter, WM_TIMER, MAKEWPARAM(1234,0), 0);
  582. short mybuf[32768] = {0};
  583. size_t mysamps = 0;
  584. if (WaitForSingleObject(cf_mutex, INFINITE) == WAIT_OBJECT_0) {
  585. if (Input_CurSelPos != -1) {
  586. if (InputDevice == 0) {
  587. if (isplaying != 1) {
  588. // when stopped or paused, we need to pump silent output
  589. // and from testing, sending 2 emtpy samples appears to
  590. // keep the output bitrate about the same as playback's
  591. mysamps = sizeof(mybuf)/8;
  592. } else {
  593. mysamps = Crossfader->get(mybuf, sizeof (mybuf) / (InputConfig.nch * sizeof (short)), InputConfig.nch) * InputConfig.nch;
  594. }
  595. } else {
  596. int samps = (LineInputAttribs[Input_CurSelPos].nch * sizeof (short));
  597. if(LineInputAttribs[Input_CurSelPos].nch == 1) {
  598. mysamps = Crossfader->get(mybuf, (samps ? sizeof (mybuf) / samps : sizeof (mybuf)) / 2, LineInputAttribs[Input_CurSelPos].nch) * LineInputAttribs[Input_CurSelPos].nch;
  599. short *newbuf = (short*) malloc(mysamps * 2 * sizeof(short));
  600. interleave_buffer(mybuf, newbuf, mysamps);
  601. mysamps *= 2;
  602. memcpy(mybuf, newbuf, mysamps * sizeof (short));
  603. free(newbuf);
  604. } else {
  605. mysamps = Crossfader->get(mybuf, (samps ? sizeof (mybuf) / samps : sizeof (mybuf)), LineInputAttribs[Input_CurSelPos].nch) * LineInputAttribs[Input_CurSelPos].nch;
  606. }
  607. }
  608. }
  609. ReleaseMutex(cf_mutex);
  610. }
  611. if (mysamps > 0) {
  612. short *tmp = mybuf;
  613. for (size_t k = 0; k != NUM_ENCODERS; k++) {
  614. if (WaitForSingleObject(Enc_mutex[k], INFINITE) == WAIT_OBJECT_0) {
  615. size_t size = mysamps * sizeof (short);
  616. short * newbuf = (short*) malloc(size);
  617. if (newbuf) {
  618. memcpy(newbuf, tmp, size);
  619. Encoder[k].Run(OM_ENCODE, newbuf, size, k); // this seems to be modifying newbuf
  620. free(newbuf);
  621. }
  622. ReleaseMutex(Enc_mutex[k]);
  623. }
  624. }
  625. }
  626. Sleep(25);
  627. } while (hthread != NULL);
  628. return 0;
  629. }
  630. DWORD WINAPI ThreadOutput(LPVOID lpParameter) {
  631. do {
  632. for (int k = 0; k < NUM_ENCODERS; k++) {
  633. if (WaitForSingleObject(Enc_mutex[k], 25) == WAIT_OBJECT_0) {
  634. if (Encoder[k].GetEncoder()) {
  635. Encoder[k].Run(OM_OUTPUT | OM_OTHER);
  636. }
  637. ReleaseMutex(Enc_mutex[k]);
  638. }
  639. }
  640. Sleep(25);
  641. } while (hthreadout != NULL);
  642. return 0;
  643. }
  644. char olddev[256] = {0};
  645. int DisplayDeviceName(void) {
  646. if (InputDevice) {
  647. char deviceBuf[256] = {0};
  648. char *deviceName = Soundcard.getDeviceName(0);
  649. if (deviceName && *deviceName) {
  650. char tmp[128] = {0};
  651. StringCchPrintfA(deviceBuf, ARRAYSIZE(deviceBuf), WASABI_API_LNGSTRING_BUF(IDS_DEVICE_STRING, tmp, 128), deviceName);
  652. } else {
  653. WASABI_API_LNGSTRING_BUF(IDS_NO_DEVICES_FOUND, deviceBuf, ARRAYSIZE(deviceBuf));
  654. olddev[0] = 0;
  655. }
  656. SendDlgItemMessage(wnd[2].hWnd, IDC_CURDEVICE, WM_SETTEXT, 0,(LPARAM)deviceBuf);
  657. // vista - 7 check for default device and restart soundcard if needed
  658. if (IsVistaUp()) {
  659. if (strcmp(deviceBuf, olddev) != 0) {
  660. lstrcpyn(olddev, deviceBuf, ARRAYSIZE(olddev));
  661. SuspendThread(hthread);
  662. Soundcard.Close();
  663. Soundcard.Create((InputDevice == 0 ? InputConfig.srate : LineInputAttribs[Input_CurSelPos].srate), (InputDevice == 0 ? InputConfig.nch : LineInputAttribs[Input_CurSelPos].nch));
  664. ResumeThread(hthread);
  665. ini_modified = 1;
  666. }
  667. }
  668. } else {
  669. SendDlgItemMessage(wnd[2].hWnd, IDC_CURDEVICE, WM_SETTEXT, 0,(LPARAM)"");
  670. }
  671. return 1;
  672. }
  673. #ifdef CAPTURE_TESTING
  674. //-----------------------------------------------------------
  675. // The input argument to this function is a pointer to the
  676. // IMMDevice interface for a capture endpoint device. The
  677. // function traverses the data path that extends from the
  678. // endpoint device to the system bus (for example, PCI)
  679. // or external bus (USB). If the function discovers a MUX
  680. // (input selector) in the path, it selects the MUX input
  681. // that connects to the stream from the endpoint device.
  682. //-----------------------------------------------------------
  683. #define EXIT_ON_ERROR(hres) \
  684. if (FAILED(hres)) { goto Exit; }
  685. #define SAFE_RELEASE(punk) \
  686. if ((punk) != NULL) \
  687. { (punk)->Release(); (punk) = NULL; }
  688. const IID IID_IDeviceTopology = __uuidof(IDeviceTopology);
  689. const IID IID_IPart = __uuidof(IPart);
  690. const IID IID_IConnector = __uuidof(IConnector);
  691. const IID IID_IAudioInputSelector = __uuidof(IAudioInputSelector);
  692. HRESULT SelectCaptureDevice(IMMDevice *pEndptDev)
  693. {
  694. HRESULT hr = S_OK;
  695. DataFlow flow;
  696. IDeviceTopology *pDeviceTopology = NULL;
  697. IConnector *pConnFrom = NULL;
  698. IConnector *pConnTo = NULL;
  699. IPart *pPartPrev = NULL;
  700. IPart *pPartNext = NULL;
  701. IAudioInputSelector *pSelector = NULL;
  702. if (pEndptDev == NULL)
  703. {
  704. EXIT_ON_ERROR(hr = E_POINTER)
  705. }
  706. // Get the endpoint device's IDeviceTopology interface.
  707. hr = pEndptDev->Activate(
  708. IID_IDeviceTopology, CLSCTX_ALL, NULL,
  709. (void**)&pDeviceTopology);
  710. EXIT_ON_ERROR(hr)
  711. // The device topology for an endpoint device always
  712. // contains just one connector (connector number 0).
  713. hr = pDeviceTopology->GetConnector(0, &pConnFrom);
  714. SAFE_RELEASE(pDeviceTopology)
  715. EXIT_ON_ERROR(hr)
  716. // Make sure that this is a capture device.
  717. hr = pConnFrom->GetDataFlow(&flow);
  718. EXIT_ON_ERROR(hr)
  719. if (flow != Out)
  720. {
  721. // Error -- this is a rendering device.
  722. EXIT_ON_ERROR(hr = AUDCLNT_E_WRONG_ENDPOINT_TYPE)
  723. }
  724. // Outer loop: Each iteration traverses the data path
  725. // through a device topology starting at the input
  726. // connector and ending at the output connector.
  727. while (TRUE)
  728. {
  729. BOOL bConnected;
  730. hr = pConnFrom->IsConnected(&bConnected);
  731. EXIT_ON_ERROR(hr)
  732. // Does this connector connect to another device?
  733. if (bConnected == FALSE)
  734. {
  735. // This is the end of the data path that
  736. // stretches from the endpoint device to the
  737. // system bus or external bus. Verify that
  738. // the connection type is Software_IO.
  739. ConnectorType connType;
  740. hr = pConnFrom->GetType(&connType);
  741. EXIT_ON_ERROR(hr)
  742. if (connType == Software_IO)
  743. {
  744. break; // finished
  745. }
  746. EXIT_ON_ERROR(hr = E_FAIL)
  747. }
  748. // Get the connector in the next device topology,
  749. // which lies on the other side of the connection.
  750. hr = pConnFrom->GetConnectedTo(&pConnTo);
  751. EXIT_ON_ERROR(hr)
  752. SAFE_RELEASE(pConnFrom)
  753. // Get the connector's IPart interface.
  754. hr = pConnTo->QueryInterface(
  755. IID_IPart, (void**)&pPartPrev);
  756. EXIT_ON_ERROR(hr)
  757. SAFE_RELEASE(pConnTo)
  758. // Inner loop: Each iteration traverses one link in a
  759. // device topology and looks for input multiplexers.
  760. while (TRUE)
  761. {
  762. PartType parttype;
  763. UINT localId;
  764. IPartsList *pParts;
  765. // Follow downstream link to next part.
  766. hr = pPartPrev->EnumPartsOutgoing(&pParts);
  767. EXIT_ON_ERROR(hr)
  768. hr = pParts->GetPart(0, &pPartNext);
  769. pParts->Release();
  770. EXIT_ON_ERROR(hr)
  771. hr = pPartNext->GetPartType(&parttype);
  772. EXIT_ON_ERROR(hr)
  773. if (parttype == Connector)
  774. {
  775. // We've reached the output connector that
  776. // lies at the end of this device topology.
  777. hr = pPartNext->QueryInterface(
  778. IID_IConnector,
  779. (void**)&pConnFrom);
  780. EXIT_ON_ERROR(hr)
  781. SAFE_RELEASE(pPartPrev)
  782. SAFE_RELEASE(pPartNext)
  783. break;
  784. }
  785. // Failure of the following call means only that
  786. // the part is not a MUX (input selector).
  787. hr = pPartNext->Activate(
  788. CLSCTX_ALL,
  789. IID_IAudioInputSelector,
  790. (void**)&pSelector);
  791. if (hr == S_OK)
  792. {
  793. // We found a MUX (input selector), so select
  794. // the input from our endpoint device.
  795. hr = pPartPrev->GetLocalId(&localId);
  796. EXIT_ON_ERROR(hr)
  797. hr = pSelector->SetSelection(localId, NULL);
  798. EXIT_ON_ERROR(hr)
  799. SAFE_RELEASE(pSelector)
  800. }
  801. SAFE_RELEASE(pPartPrev)
  802. pPartPrev = pPartNext;
  803. pPartNext = NULL;
  804. }
  805. }
  806. Exit:
  807. SAFE_RELEASE(pConnFrom)
  808. SAFE_RELEASE(pConnTo)
  809. SAFE_RELEASE(pPartPrev)
  810. SAFE_RELEASE(pPartNext)
  811. SAFE_RELEASE(pSelector)
  812. return hr;
  813. }
  814. #endif
  815. void setlev(int cs, int va) {
  816. if (IsVistaUp() &&
  817. (cs == MIXERLINE_COMPONENTTYPE_SRC_LINE || cs == MIXERLINE_COMPONENTTYPE_SRC_MICROPHONE)) {
  818. //HRESULT hr = S_OK;
  819. IMMDeviceEnumerator *pEnumerator = NULL;
  820. IMMDevice *pDevice = NULL;
  821. IMMDeviceCollection *ppDevices = NULL;
  822. //hr = CoCreateGuid(&g_guidMyContext);
  823. //EXIT_ON_ERROR(hr)
  824. // Get enumerator for audio endpoint devices.
  825. CoInitializeEx(NULL, COINIT_APARTMENTTHREADED);
  826. HRESULT hr = CoCreateInstance(__uuidof(MMDeviceEnumerator),
  827. NULL, CLSCTX_INPROC_SERVER,
  828. __uuidof(IMMDeviceEnumerator),
  829. (void**)&pEnumerator);
  830. EXIT_ON_ERROR(hr)
  831. hr = pEnumerator->EnumAudioEndpoints(eCapture, DEVICE_STATE_ACTIVE | DEVICE_STATE_UNPLUGGED, &ppDevices);
  832. EXIT_ON_ERROR(hr)
  833. hr = ppDevices->Item(Input_Device_ID, &pDevice);
  834. EXIT_ON_ERROR(hr)
  835. //activate
  836. hr = pDevice->Activate(__uuidof(IAudioEndpointVolume), CLSCTX_ALL, NULL, (void**)&g_pEndptVol);
  837. EXIT_ON_ERROR(hr)
  838. //set mic volume
  839. float fVolume = (float)(va / 100.0f);
  840. if (va > 2) {
  841. hr = g_pEndptVol->SetMasterVolumeLevelScalar(fVolume, NULL/*&g_guidMyContext*/);
  842. EXIT_ON_ERROR(hr)
  843. } else {//mute
  844. hr = g_pEndptVol->SetMasterVolumeLevelScalar((float)0.0f, NULL/*&g_guidMyContext*/);
  845. }
  846. /*hr = pDevice->Activate(__uuidof(IAudioStreamVolume ), CLSCTX_ALL, NULL, (void**)&g_pStreamVol);
  847. EXIT_ON_ERROR(hr)
  848. g_pStreamVol->SetChannelVolume(0, fVolume);
  849. g_pStreamVol->SetChannelVolume(1, fVolume);
  850. IMMDevice *pDefaultDevice = NULL;
  851. hr = pEnumerator->GetDefaultAudioEndpoint(eCapture,eConsole,&pDefaultDevice);
  852. EXIT_ON_ERROR(hr)
  853. hr = pDefaultDevice->Activate(__uuidof(IAudioStreamVolume ), CLSCTX_ALL, NULL, (void**)&g_pStreamVol);
  854. EXIT_ON_ERROR(hr)
  855. g_pStreamVol->SetChannelVolume(0, fVolume);
  856. g_pStreamVol->SetChannelVolume(1, fVolume);*/
  857. Exit:
  858. SAFE_RELEASE(pEnumerator)
  859. SAFE_RELEASE(pDevice)
  860. SAFE_RELEASE(ppDevices)
  861. SAFE_RELEASE(g_pEndptVol)
  862. CoUninitialize();
  863. } // end if mic
  864. for (UINT i = 0; i < (IsVistaUp() ? mixerGetNumDevs() : 1); i++) {
  865. HMIXER hmix;
  866. #ifdef FOLLOW_MIXER
  867. // TODO use a different handle??
  868. mixerOpen(&hmix, i, (DWORD_PTR)hMainDLG, 0, MIXER_OBJECTF_MIXER|CALLBACK_WINDOW);
  869. #endif
  870. if (mixerOpen(&hmix, i, (DWORD_PTR)hMainDLG, 0, MIXER_OBJECTF_MIXER) == MMSYSERR_NOERROR) {
  871. MIXERLINE ml = {sizeof (ml), 0};
  872. ml.dwComponentType = cs;
  873. if (mixerGetLineInfo((HMIXEROBJ) hmix, &ml, MIXER_GETLINEINFOF_COMPONENTTYPE|MIXER_OBJECTF_MIXER) == MMSYSERR_NOERROR) {
  874. MIXERLINECONTROLS mlc = {sizeof (mlc), ml.dwLineID,};
  875. MIXERCONTROL mc = {sizeof (mc),};
  876. mlc.cControls = 1;
  877. mlc.cbmxctrl = sizeof (mc);
  878. mlc.pamxctrl = &mc;
  879. mlc.dwControlType = MIXERCONTROL_CONTROLTYPE_VOLUME;
  880. if (mixerGetLineControls((HMIXEROBJ) hmix, &mlc, MIXER_GETLINECONTROLSF_ONEBYTYPE|MIXER_OBJECTF_MIXER) == MMSYSERR_NOERROR) {
  881. MIXERCONTROLDETAILS mcd = {sizeof (mcd), mc.dwControlID, ml.cChannels,};
  882. MIXERCONTROLDETAILS_UNSIGNED v[2];
  883. mcd.cbDetails = sizeof (MIXERCONTROLDETAILS_UNSIGNED);
  884. mcd.paDetails = v;
  885. v[0].dwValue = mc.Bounds.dwMinimum + (va * (mc.Bounds.dwMaximum - mc.Bounds.dwMinimum)) / 100;
  886. v[1].dwValue = mc.Bounds.dwMinimum + (va * (mc.Bounds.dwMaximum - mc.Bounds.dwMinimum)) / 100;
  887. /*MMRESULT result = */mixerSetControlDetails((HMIXEROBJ) hmix, &mcd, MIXER_OBJECTF_MIXER);
  888. }
  889. }
  890. mixerClose(hmix);
  891. }
  892. }
  893. DisplayDeviceName();
  894. }
  895. int SetDeviceName(void) {
  896. HRESULT hr = S_OK;
  897. IMMDeviceEnumerator *pEnumerate = NULL;
  898. IMMDevice *pDevice = NULL;
  899. IMMDevice *pDefaultDevice = NULL;
  900. IMMDeviceCollection *ppDevices = NULL;
  901. IPropertyStore *pProps = NULL;
  902. PROPVARIANT varName;
  903. if (IsVistaUp()) {
  904. CoInitializeEx(NULL, COINIT_APARTMENTTHREADED);
  905. PropVariantInit(&varName);
  906. // Get enumerator for audio endpoint devices.
  907. hr = CoCreateInstance(__uuidof(MMDeviceEnumerator),
  908. NULL, CLSCTX_INPROC_SERVER,
  909. __uuidof(IMMDeviceEnumerator),
  910. (void**)&pEnumerate);
  911. EXIT_ON_ERROR(hr)
  912. hr = pEnumerate->EnumAudioEndpoints(eCapture, DEVICE_STATE_ACTIVE | DEVICE_STATE_UNPLUGGED, &ppDevices);
  913. EXIT_ON_ERROR(hr)
  914. numInputs = 0;
  915. hr = ppDevices->GetCount(&numInputs);
  916. EXIT_ON_ERROR(hr)
  917. // treat this as a dummy stop
  918. Exit:;
  919. }
  920. int oldCount = SendDlgItemMessage(inWin, IDC_DEVBOX, CB_GETCOUNT, 0, 0);
  921. SendDlgItemMessage(inWin, IDC_DEVBOX, CB_RESETCONTENT, 0,0);
  922. EnableWindowDlgItem(inWin, IDC_REFRESH_DEVICES, IsVistaUp());
  923. if (!IsVistaUp()) {//change back to true when vista enabled !
  924. SendDlgItemMessageW(inWin, IDC_DEVBOX, CB_ADDSTRING, 0,(LPARAM)LocalisedString(IDS_MIC_LEGACY_MODE, NULL, 0));
  925. SendDlgItemMessageW(inWin, IDC_DEVBOX, CB_ADDSTRING, 0,(LPARAM)LocalisedString(IDS_LINEIN_LEGACY_MODE, NULL, 0));
  926. } else {
  927. hr = pEnumerate->GetDefaultAudioEndpoint(eCapture, eConsole, &pDefaultDevice);
  928. if (SUCCEEDED(hr) && pDefaultDevice != NULL) {
  929. LPWSTR defaultName = NULL;
  930. pDefaultDevice->GetId(&defaultName);
  931. //jkey: This is for vista or 7, so we scan through and add friendly device names
  932. // though need to make sure that we don't re-add the current input device
  933. // otherwise with the waveout fudge we'll get really bad feedback on output
  934. for (unsigned int i=0; i < numInputs; i++) {
  935. LPWSTR itemName = NULL;
  936. ppDevices->Item(i, &pDevice);
  937. pDevice->GetId(&itemName);
  938. // check the id of the endpoints to prevent adding in the default output device
  939. if (defaultName && wcsicmp(itemName, defaultName)) {
  940. pDevice->OpenPropertyStore(STGM_READ, &pProps);
  941. pProps->GetValue(PKEY_Device_FriendlyName, &varName);
  942. SendDlgItemMessageW(inWin, IDC_DEVBOX, CB_ADDSTRING, 0,(LPARAM)varName.pwszVal);
  943. SendDlgItemMessage(inWin, IDC_DEVBOX, CB_SETITEMDATA, i,(LPARAM)i);
  944. }
  945. CoTaskMemFree(itemName);
  946. }
  947. CoTaskMemFree(defaultName);
  948. }
  949. int count = SendDlgItemMessage(inWin, IDC_DEVBOX, CB_GETCOUNT, 0, 0);
  950. if (!count) {
  951. SendDlgItemMessageW(inWin, IDC_DEVBOX, CB_ADDSTRING, 0, (LPARAM)WASABI_API_LNGSTRINGW(IDS_NO_CAPTURE_DEVICES));
  952. }
  953. EnableWindowDlgItem(inWin, IDC_DEVBOX, count);
  954. // reset to the first item in the list if there's any changes
  955. if (!oldCount || count != oldCount) {
  956. SendDlgItemMessage(inWin, IDC_DEVBOX, CB_SETCURSEL, 0, 0);
  957. }
  958. PropVariantClear(&varName);
  959. SAFE_RELEASE(pProps)
  960. SAFE_RELEASE(pEnumerate)
  961. SAFE_RELEASE(pDevice)
  962. SAFE_RELEASE(ppDevices)
  963. CoUninitialize();
  964. }
  965. SendDlgItemMessage(inWin, IDC_DEVBOX, CB_SETCURSEL, Input_Device_ID, 0);
  966. DisplayDeviceName();
  967. return 1;
  968. }
  969. /*int getlev(int cs) {
  970. HMIXER hmix;
  971. int retval = -1;
  972. #ifdef USE_VISTA_SOUND_FIX
  973. HRESULT hr = S_OK;
  974. IMMDeviceEnumerator *pEnumerator = NULL;
  975. IMMDevice *pDevice = NULL;
  976. IMMDeviceCollection *ppDevices = NULL;
  977. hr = CoCreateGuid(&g_guidMyContext);
  978. EXIT_ON_ERROR(hr)
  979. // Get enumerator for audio endpoint devices.
  980. CoInitializeEx(NULL, COINIT_APARTMENTTHREADED);
  981. hr = CoCreateInstance(__uuidof(MMDeviceEnumerator),
  982. NULL, CLSCTX_INPROC_SERVER,
  983. __uuidof(IMMDeviceEnumerator),
  984. (void**)&pEnumerator);
  985. EXIT_ON_ERROR(hr)
  986. hr = pEnumerator->EnumAudioEndpoints(eCapture,DEVICE_STATE_ACTIVE,&ppDevices);
  987. EXIT_ON_ERROR(hr)
  988. hr = ppDevices->Item(Input_Device_ID,&pDevice);
  989. EXIT_ON_ERROR(hr)
  990. //activate
  991. hr = pDevice->Activate(__uuidof(IAudioEndpointVolume),
  992. CLSCTX_ALL, NULL, (void**)&g_pEndptVol);
  993. EXIT_ON_ERROR(hr)
  994. //set mic volume
  995. float fVolume =0.0;
  996. hr = g_pEndptVol->GetMasterVolumeLevel(&fVolume);
  997. EXIT_ON_ERROR(hr)
  998. Exit:
  999. if (FAILED(hr)) {
  1000. useXpSound = true;
  1001. } else {
  1002. retval = (int)fVolume * 100;
  1003. return retval;
  1004. }
  1005. SAFE_RELEASE(pEnumerator)
  1006. SAFE_RELEASE(pDevice)
  1007. SAFE_RELEASE(ppDevices)
  1008. SAFE_RELEASE(g_pEndptVol)
  1009. CoUninitialize();
  1010. #endif //USE_VISTA_SOUND_FIX
  1011. if (mixerOpen(&hmix, 0, 0, 0, 0) == MMSYSERR_NOERROR) {
  1012. MIXERLINE ml = {sizeof (ml), 0};
  1013. ml.dwComponentType = cs;
  1014. if (mixerGetLineInfo((HMIXEROBJ) hmix, &ml, MIXER_GETLINEINFOF_COMPONENTTYPE) == MMSYSERR_NOERROR) {
  1015. MIXERLINECONTROLS mlc = {sizeof (mlc), ml.dwLineID,};
  1016. MIXERCONTROL mc = {sizeof (mc),};
  1017. mlc.cControls = 1;
  1018. mlc.cbmxctrl = sizeof (mc);
  1019. mlc.pamxctrl = &mc;
  1020. mlc.dwControlType = MIXERCONTROL_CONTROLTYPE_VOLUME;
  1021. if (mixerGetLineControls((HMIXEROBJ) hmix, &mlc, MIXER_GETLINECONTROLSF_ONEBYTYPE) == MMSYSERR_NOERROR) {
  1022. MIXERCONTROLDETAILS mcd = {sizeof (mcd), mc.dwControlID, ml.cChannels,};
  1023. MIXERCONTROLDETAILS_UNSIGNED v[2];
  1024. mcd.cbDetails = sizeof (MIXERCONTROLDETAILS_UNSIGNED);
  1025. mcd.paDetails = v;
  1026. if (mixerGetControlDetails((HMIXEROBJ) hmix, &mcd, 0) == MMSYSERR_NOERROR) {
  1027. retval = (v[0].dwValue * 100) / (mc.Bounds.dwMaximum - mc.Bounds.dwMinimum);
  1028. // retval = ((v[0].dwValue + v[1].dwValue) * 5) / (mc.Bounds.dwMaximum-mc.Bounds.dwMinimum);
  1029. }
  1030. }
  1031. }
  1032. mixerClose(hmix);
  1033. }
  1034. return retval;
  1035. }*/
  1036. void TitleCallback(int Connection, int Mode) {
  1037. MY_T_OUTPUT *Out = &Output[Connection];
  1038. // title update
  1039. if (Mode == 0) {
  1040. if (Out->AutoTitle == 1) {
  1041. // look at the playback queue so we can get the correct 'next song'
  1042. if (!WASABI_API_QUEUEMGR) {
  1043. // due to loading orders its possible the queue won't have been loaded on init so check
  1044. ServiceBuild(WASABI_API_SVC, WASABI_API_QUEUEMGR, QueueManagerApiGUID);
  1045. }
  1046. std::vector<std::wstring> nextList;
  1047. nextList.clear();
  1048. Encoder[Out->Encoder].UpdateTitle(0, nextList, Out->Handle, !!Out->NextTitles);
  1049. }
  1050. } else if (Mode == 1) {
  1051. // album art update
  1052. Encoder[Out->Encoder].UpdateAlbumArt(Out->Handle);
  1053. }
  1054. }
  1055. void CenterWindow(void) {
  1056. RECT rect, rectP;
  1057. int width, height;
  1058. int screenwidth, screenheight;
  1059. int x, y;
  1060. GetWindowRect(hMainDLG, &rect);
  1061. GetWindowRect(GetDesktopWindow(), &rectP);
  1062. width = rect.right - rect.left;
  1063. height = rect.bottom - rect.top;
  1064. x = ((rectP.right-rectP.left) - width) / 2 + rectP.left;
  1065. y = ((rectP.bottom-rectP.top) - height) / 2 + rectP.top;
  1066. screenwidth = GetSystemMetrics(SM_CXSCREEN);
  1067. screenheight = GetSystemMetrics(SM_CYSCREEN);
  1068. if (x < 0) x = 0;
  1069. if (y < 0) y = 0;
  1070. if (x + width > screenwidth) x = screenwidth - width;
  1071. if (y + height > screenheight) y = screenheight - height;
  1072. mainrect.left = x;
  1073. mainrect.top = y;
  1074. }
  1075. int LoadConfig(void) {
  1076. lookAhead = GetPrivateProfileInt(APP_Name, "lookAhead", lookAhead, IniName);
  1077. skipMetada = !!GetPrivateProfileInt(APP_Name, "skipMetada", skipMetada, IniName);
  1078. lastFilterIndex = GetPrivateProfileInt(APP_Name, "ofnidx", lastFilterIndex, IniName);
  1079. curtab = GetPrivateProfileInt(APP_Name, "CurTab", curtab, IniName);
  1080. Connection_CurSelPos = GetPrivateProfileInt(APP_Name, "Connection_CurSelPos", Connection_CurSelPos, IniName);
  1081. curouttab = GetPrivateProfileInt(APP_Name, "Connection_CurTab", curouttab, IniName);
  1082. Encoder_CurSelPos = GetPrivateProfileInt(APP_Name, "Encoder_CurSelPos", Encoder_CurSelPos, IniName);
  1083. InputDevice = GetPrivateProfileInt(APP_Name, "InputDevice", InputDevice, IniName);
  1084. Input_CurSelPos = GetPrivateProfileInt(APP_Name, "Input_CurSelPos", Input_CurSelPos, IniName);
  1085. InputConfig.srate = LineInputAttribs[3].srate;
  1086. InputConfig.nch = LineInputAttribs[3].nch;
  1087. cf_mutex = CreateMutex(NULL, TRUE, NULL);
  1088. Crossfader = new C_CROSSFADER(CrossfadeLen,
  1089. LineInputAttribs[(InputDevice == 0 ? 3 : Input_CurSelPos)].nch,
  1090. LineInputAttribs[(InputDevice == 0 ? 3 : Input_CurSelPos)].srate);
  1091. MusVol = GetPrivateProfileInt(APP_Name, "MusicVolume", MusVol, IniName);
  1092. Mus2Vol = GetPrivateProfileInt(APP_Name, "BGMusicVolume", Mus2Vol, IniName);
  1093. MicVol = GetPrivateProfileInt(APP_Name, "MicVolume", MicVol, IniName);
  1094. // as we've changed the scaling then we will need to adjust from old to new
  1095. int tempFadeTime = GetPrivateProfileInt(APP_Name, "PTT_FadeTime", -1, IniName);
  1096. if (tempFadeTime == -1) {
  1097. FadeTime = GetPrivateProfileInt(APP_Name, "PTT_FT", FadeTime, IniName);
  1098. } else {
  1099. FadeTime = tempFadeTime * 5;
  1100. // remove the old instance of the settings
  1101. WritePrivateProfileString(APP_Name, "PTT_FadeTime", 0, IniName);
  1102. }
  1103. int tempMicFadeTime = GetPrivateProfileInt(APP_Name, "PTT_MicFadeTime", -1, IniName);
  1104. if (tempMicFadeTime == -1) {
  1105. MicFadeTime = GetPrivateProfileInt(APP_Name, "PTT_MicFT", MicFadeTime, IniName);
  1106. } else {
  1107. MicFadeTime = tempMicFadeTime * 5;
  1108. // remove the old instance of the settings
  1109. WritePrivateProfileString(APP_Name, "PTT_MicFadeTime", 0, IniName);
  1110. }
  1111. Restore_PTT = GetPrivateProfileInt(APP_Name, "PTT_Restore", 0, IniName);
  1112. Input_Device_ID = GetPrivateProfileInt(APP_Name, "PTT_MicInput",0, IniName);
  1113. // align to middle of screen on new installs
  1114. CenterWindow();
  1115. mainrect.left = GetPrivateProfileInt(APP_Name, "WindowLeft", mainrect.left, IniName);
  1116. mainrect.top = GetPrivateProfileInt(APP_Name, "WindowTop", mainrect.top, IniName);
  1117. GetPrivateProfileString(APP_Name, "Update", 0, updateStr, 16, IniName);
  1118. // no point in indicating a new version if we're now showing as ahead
  1119. if (!CompareVersions(updateStr)) {
  1120. WritePrivateProfileString(APP_Name, "Update", 0, IniName);
  1121. updateStr[0] = 0;
  1122. }
  1123. for (int i = 0; i < NUM_OUTPUTS; i++) {
  1124. T_OUTPUT_CONFIG *Out = &Output[i].Config;
  1125. StringCchPrintfA(Out->Name, 32, "Output %u", i + 1);
  1126. StringCchPrintfW(Out->DisplayName, 32, WASABI_API_LNGSTRINGW(IDS_OUTPUT_X), i + 1);
  1127. Output[i].Encoder = -1;
  1128. Output[i].Handle = -1;
  1129. GetPrivateProfileString(Out->Name, "Address", "localhost", Out->Address, ARRAYSIZE(Out->Address), IniName);
  1130. GetPrivateProfileString(Out->Name, "UserID", "", Out->UserID, ARRAYSIZE(Out->UserID), IniName);
  1131. GetPrivateProfileString(Out->Name, "StreamID", "1", Out->StationID, ARRAYSIZE(Out->StationID), IniName);
  1132. Out->Port = GetPrivateProfileInt(Out->Name, "Port", 8000, IniName);
  1133. GetPrivateProfileString(Out->Name, "Password", "", Out->Password, ARRAYSIZE(Out->Password), IniName);
  1134. GetPrivateProfileString(Out->Name, "Cipherkey", "foobar", Out->cipherkey, ARRAYSIZE(Out->cipherkey), IniName);
  1135. GetPrivateProfileString(Out->Name, "Description", "Unnamed Server", Out->Description, ARRAYSIZE(Out->Description), IniName);
  1136. GetPrivateProfileString(Out->Name, "URL", "http://www.shoutcast.com", Out->ServerURL, ARRAYSIZE(Out->ServerURL), IniName);
  1137. GetPrivateProfileString(Out->Name, "Genre3", "Misc", Out->Genre, ARRAYSIZE(Out->Genre), IniName);
  1138. // check that the genre is a support value otherwise reset it to 'misc'
  1139. bool foundGenre = false;
  1140. for (int g = 0; g < ARRAYSIZE(genres); g++) {
  1141. if (!strcmpi(genres[g].name, Out->Genre)) {
  1142. foundGenre = true;
  1143. break;
  1144. }
  1145. }
  1146. if (foundGenre == false) {
  1147. lstrcpyn(Out->Genre, "Misc", ARRAYSIZE(Out->Genre));
  1148. }
  1149. GetPrivateProfileString(Out->Name, "AIM", "N/A", Out->AIM, ARRAYSIZE(Out->AIM), IniName);
  1150. GetPrivateProfileString(Out->Name, "ICQ", "0", Out->ICQ, ARRAYSIZE(Out->ICQ), IniName);
  1151. GetPrivateProfileString(Out->Name, "IRC", "N/A", Out->IRC, ARRAYSIZE(Out->IRC), IniName);
  1152. Out->Public = GetPrivateProfileInt(Out->Name, "Public", 1, IniName);
  1153. Out->AutoRecon = GetPrivateProfileInt(Out->Name, "AutoRecon", 1, IniName);
  1154. Out->ReconTime = GetPrivateProfileInt(Out->Name, "ReconTime", 5, IniName);
  1155. if (Out->ReconTime < 1) {
  1156. Out->ReconTime = 5;
  1157. }
  1158. Out->doTitleUpdate = GetPrivateProfileInt(Out->Name, "doTitleUpdate", 1, IniName);
  1159. GetPrivateProfileString(Out->Name, "now", "", Out->Now, ARRAYSIZE(Out->Now), IniName);
  1160. GetPrivateProfileString(Out->Name, "next", "", Out->Next, ARRAYSIZE(Out->Next), IniName);
  1161. Output[i].AutoTitle = GetPrivateProfileInt(Out->Name, "AutoTitle", 1, IniName);
  1162. Output[i].AutoConnect = GetPrivateProfileInt(Out->Name, "AutoConnect", 0, IniName);
  1163. Output[i].Logging = GetPrivateProfileInt(Out->Name, "Logging", 0, IniName);
  1164. Output[i].LogCOS = GetPrivateProfileInt(Out->Name, "LogCOS", 0, IniName);
  1165. Output[i].NextTitles = GetPrivateProfileInt(Out->Name, "NextTitles", 1, IniName);
  1166. Output[i].Config.protocol = GetPrivateProfileInt(Out->Name, "protocol", -1, IniName);
  1167. if (Output[i].Config.protocol == -1) {
  1168. Output[i].Config.protocol = MAKEWORD(2, 1);
  1169. }
  1170. // check the v1 password for : and split it if the dj/user id is empty (i.e. post 2.2.3 import)
  1171. if (LOBYTE(Output[i].Config.protocol) == 1 && Out->Password[0] && !Out->UserID[0]) {
  1172. char* password = strstr(Out->Password, ":");
  1173. if (password) {
  1174. *password = 0;
  1175. lstrcpyn(Out->UserID, Out->Password, ARRAYSIZE(Out->UserID));
  1176. lstrcpyn(Out->Password, ++password, ARRAYSIZE(Out->Password));
  1177. }
  1178. }
  1179. Output[i].nextTrackLog = GetPrivateProfileInt(Out->Name, "nextTrackLog", 0, IniName);
  1180. Output[i].nextTrackLogXML = GetPrivateProfileInt(Out->Name, "nextTrackLogXML", 0, IniName);
  1181. if (!GetPrivateProfileStringUTF8(Out->Name, "nextTrackPath", 0, Output[i].nextTrackPath, ARRAYSIZE(Output[i].nextTrackPath), IniName)) {
  1182. GetDefaultNextTracksLogFile(module.hwndParent, ARRAYSIZE(Output[i].nextTrackPath), Output[i].nextTrackPath, i);
  1183. }
  1184. Output[i].useArt = GetPrivateProfileInt(Out->Name, "useArt", 0, IniName);
  1185. Output[i].usePlayingArt = GetPrivateProfileInt(Out->Name, "usePlayingArt", 0, IniName);
  1186. Output[i].useStreamArt = GetPrivateProfileInt(Out->Name, "useStreamArt", 1, IniName);
  1187. GetPrivateProfileStringUTF8(Out->Name, "stationArtPath", 0, Output[i].stationArtPath, ARRAYSIZE(Output[i].stationArtPath), IniName);
  1188. Output[i].saveEncoded = GetPrivateProfileInt(Out->Name, "saveEncoded", 0, IniName);
  1189. GetPrivateProfileStringUTF8(Out->Name, "saveEncodedPath", 0, Output[i].saveEncodedPath, ARRAYSIZE(Output[i].saveEncodedPath), IniName);
  1190. Output[i].Encoder = GetPrivateProfileInt(Out->Name, "Encoder", i == 0 ? 0 : -1, IniName);
  1191. if (Output[i].Encoder != -1) {
  1192. if (WaitForSingleObject(Enc_mutex[Output[i].Encoder], INFINITE) == WAIT_OBJECT_0) {
  1193. Output[i].Handle = Encoder[Output[i].Encoder].AddOutput(i, Out, TitleCallback);
  1194. ReleaseMutex(Enc_mutex[Output[i].Encoder]);
  1195. }
  1196. }
  1197. }
  1198. return 1;
  1199. }
  1200. wchar_t* BuildLameVersion(void) {
  1201. static wchar_t version[128] = {0};
  1202. if (libinst != NULL && !version[0]) {
  1203. BE_VERSION ver;
  1204. beVersion(&ver);
  1205. if (ver.byBetaLevel) {
  1206. StringCchPrintfW(version, ARRAYSIZE(version), L"%u.%ub%u", (unsigned int)ver.byMajorVersion, (unsigned int)ver.byMinorVersion, (unsigned int)ver.byBetaLevel);
  1207. } else if (ver.byAlphaLevel) {
  1208. StringCchPrintfW(version, ARRAYSIZE(version), L"%u.%ua%u", (unsigned int)ver.byMajorVersion, (unsigned int)ver.byMinorVersion, (unsigned int)ver.byAlphaLevel);
  1209. } else {
  1210. StringCchPrintfW(version, ARRAYSIZE(version), L"%u.%u", (unsigned int)ver.byMajorVersion, (unsigned int)ver.byMinorVersion);
  1211. }
  1212. }
  1213. return version;
  1214. }
  1215. void LoadEncoders() {
  1216. /* load lame_enc.dll */
  1217. wchar_t dllname[MAX_PATH] = {0};
  1218. StringCchPrintfW(dllname, ARRAYSIZE(dllname), L"%s\\lame_enc.dll", GetSharedDirectoryW(module.hwndParent));
  1219. libinst = LoadLibraryW(dllname);
  1220. if (libinst == NULL) {
  1221. wchar_t title[128] = {0}, message[512] = {0};
  1222. StringCchPrintfW(title, ARRAYSIZE(title), LocalisedString(IDS_PLUGIN_NAME, NULL, 0), APP_VersionW);
  1223. StringCchPrintfW(message, ARRAYSIZE(message), LocalisedString(IDS_FAILED_LOAD_LAMEDLL, NULL, 0), GetSharedDirectoryW(module.hwndParent));
  1224. MessageBoxW(module.hwndParent, message, title, MB_ICONWARNING);
  1225. } else {
  1226. beVersion = (BEVERSION) GetProcAddress(libinst, "beVersion");
  1227. init = (void *) GetProcAddress(libinst, "lame_init");
  1228. params = (void *) GetProcAddress(libinst, "lame_init_params");
  1229. encode = (void *) GetProcAddress(libinst, "lame_encode_buffer_interleaved");
  1230. finish = (void *) GetProcAddress(libinst, "lame_encode_flush");
  1231. if (!init || !params || !encode || !finish) {
  1232. wchar_t title[128] = {0};
  1233. StringCchPrintfW(title, ARRAYSIZE(title), LocalisedString(IDS_PLUGIN_NAME, NULL, 0), APP_VersionW);
  1234. MessageBoxW(module.hwndParent, LocalisedString(IDS_LAMEDLL_ISSUE, NULL, 0), title, MB_ICONWARNING);
  1235. FreeLibrary(libinst);
  1236. libinst = 0;
  1237. }
  1238. }
  1239. /* load encoder type */
  1240. for (int i = 0; i < NUM_ENCODERS; i++) {
  1241. char name[32] = {0};
  1242. Enc_mutex[i] = CreateMutex(NULL, TRUE, NULL);
  1243. StringCchPrintfA(name, ARRAYSIZE(name), "Encoder %u", i + 1);
  1244. int EncType = GetPrivateProfileInt(name, "Type", 2, IniName);
  1245. // store our type for later on
  1246. Enc_LastType[i] = EncType;
  1247. switch (EncType) {
  1248. /* mp3 */
  1249. case 1:
  1250. {
  1251. fallback:
  1252. Encoder[i].SetLame(init, params, encode, finish);
  1253. Encoder[i].SetEncoder(DEFAULT_ENCODER);
  1254. C_ENCODER *Enc = Encoder[i].GetEncoder();
  1255. if (Enc) {
  1256. if (strcmp(Enc->GetName(), "MP3 Encoder") == 0) {
  1257. T_ENCODER_MP3_INFO EncSettings;
  1258. int infosize = sizeof (EncSettings);
  1259. T_ENCODER_MP3_INFO *encset = (T_ENCODER_MP3_INFO *) Enc->GetExtInfo(&infosize);
  1260. if (encset && infosize) memcpy(&EncSettings, encset, infosize);
  1261. EncSettings.input_numChannels = (InputDevice == 0 ? InputConfig.nch : LineInputAttribs[Input_CurSelPos].nch);
  1262. EncSettings.input_sampleRate = (InputDevice == 0 ? InputConfig.srate : LineInputAttribs[Input_CurSelPos].srate);
  1263. EncSettings.output_bitRate = GetPrivateProfileInt(name, "BitRate", EncSettings.output_bitRate, IniName);
  1264. EncSettings.output_sampleRate = GetPrivateProfileInt(name, "SampleRate", EncSettings.output_sampleRate, IniName);
  1265. EncSettings.output_numChannels = GetPrivateProfileInt(name, "NumChannels", EncSettings.output_numChannels, IniName);
  1266. EncSettings.QualityMode = GetPrivateProfileInt(name, "QualityMode", 8, IniName);
  1267. Enc->ChangeSettings(&EncSettings);
  1268. }
  1269. }
  1270. }
  1271. break;
  1272. case 2:
  1273. // map any AAC LC from the prior versions to FHG AAC with 5.62+
  1274. case 3:
  1275. { // FHG AAC
  1276. if (C_ENCODER_FHGAAC::isPresent(module.hwndParent)) {
  1277. Encoder[i].SetEncoder(new C_ENCODER_FHGAAC(module.hwndParent), 1);
  1278. C_ENCODER *Enc = Encoder[i].GetEncoder();
  1279. if (Enc) {
  1280. T_ENCODER_FHGAAC_INFO EncSettings;
  1281. int infosize = sizeof (EncSettings);
  1282. T_ENCODER_FHGAAC_INFO *encset = (T_ENCODER_FHGAAC_INFO *) Enc->GetExtInfo(&infosize);
  1283. if (encset && infosize) memcpy(&EncSettings, encset, infosize);
  1284. EncSettings.input_numChannels = (InputDevice == 0 ? InputConfig.nch : LineInputAttribs[Input_CurSelPos].nch);
  1285. EncSettings.input_sampleRate = (InputDevice == 0 ? InputConfig.srate : LineInputAttribs[Input_CurSelPos].srate);
  1286. Enc->ChangeSettings(&EncSettings);
  1287. ((C_ENCODER_NSV*) Enc)->ReadConfFile(IniName, name);
  1288. }
  1289. } else if (C_ENCODER_AACP::isPresent(module.hwndParent)) { // AAC+
  1290. Encoder[i].SetEncoder(new C_ENCODER_AACP(module.hwndParent), 1);
  1291. C_ENCODER *Enc = Encoder[i].GetEncoder();
  1292. if (Enc) {
  1293. T_ENCODER_AACP_INFO EncSettings;
  1294. int infosize = sizeof (EncSettings);
  1295. T_ENCODER_AACP_INFO *encset = (T_ENCODER_AACP_INFO *) Enc->GetExtInfo(&infosize);
  1296. if (encset && infosize) memcpy(&EncSettings, encset, infosize);
  1297. EncSettings.input_numChannels = (InputDevice == 0 ? InputConfig.nch : LineInputAttribs[Input_CurSelPos].nch);
  1298. EncSettings.input_sampleRate = (InputDevice == 0 ? InputConfig.srate : LineInputAttribs[Input_CurSelPos].srate);
  1299. Enc->ChangeSettings(&EncSettings);
  1300. ((C_ENCODER_NSV*) Enc)->ReadConfFile(IniName, name);
  1301. }
  1302. } else {
  1303. //Encoder[i].SetEncoder(NULL);
  1304. // attempt to get to a valid encoder if the aac one disappeared
  1305. goto fallback;
  1306. }
  1307. }
  1308. break;
  1309. #ifdef USE_OGG
  1310. case 4:
  1311. { // OGG
  1312. if (C_ENCODER_OGG::isPresent(module.hwndParent)) {
  1313. Encoder[i].SetEncoder(new C_ENCODER_OGG(module.hwndParent), 1);
  1314. C_ENCODER *Enc = Encoder[i].GetEncoder();
  1315. if (Enc) {
  1316. T_ENCODER_OGG_INFO EncSettings;
  1317. int infosize = sizeof (EncSettings);
  1318. T_ENCODER_OGG_INFO *encset = (T_ENCODER_OGG_INFO *) Enc->GetExtInfo(&infosize);
  1319. if (encset && infosize) memcpy(&EncSettings, encset, infosize);
  1320. EncSettings.input_numChannels = (InputDevice == 0 ? InputConfig.nch : LineInputAttribs[Input_CurSelPos].nch);
  1321. EncSettings.input_sampleRate = (InputDevice == 0 ? InputConfig.srate : LineInputAttribs[Input_CurSelPos].srate);
  1322. Enc->ChangeSettings(&EncSettings);
  1323. ((C_ENCODER_NSV*) Enc)->ReadConfFile(IniName, name);
  1324. }
  1325. } else Encoder[i].SetEncoder(NULL);
  1326. }
  1327. break;
  1328. #endif // USE_OGG
  1329. default:
  1330. {
  1331. Encoder[i].SetEncoder(NULL);
  1332. }
  1333. break;
  1334. }
  1335. ReleaseMutex(Enc_mutex[i]);
  1336. }
  1337. }
  1338. void SetEncoderPanelMode(HWND hDlg, C_ENCODER * Enc) {
  1339. BOOL show = (Enc != NULL);
  1340. if (show) {
  1341. if (Enc->UseNsvConfig() == true) {
  1342. ShowWindowDlgItem(hDlg, IDC_ENCSETTINGS, SW_HIDE);
  1343. ShowWindowDlgItem(hDlg, IDC_ENCSETTINGS_BUTTON, SW_SHOW);
  1344. wchar_t tmp[128] = {0};
  1345. StringCchPrintfW(tmp, ARRAYSIZE(tmp), LocalisedString(IDS_CURRENT_BITRATE, NULL, 0), ((T_EncoderIOVals*) Enc->GetExtInfo())->output_bitRate);
  1346. SetDlgItemTextW(hDlg, IDC_ENCSETTINGS_LABEL, tmp);
  1347. ShowWindowDlgItem(hDlg, IDC_ENCSETTINGS_LAME_VER, SW_HIDE);
  1348. } else {
  1349. wchar_t *lame_version = BuildLameVersion();
  1350. if (lame_version && *lame_version)
  1351. {
  1352. ShowWindowDlgItem(hDlg, IDC_ENCSETTINGS, SW_SHOW);
  1353. ShowWindowDlgItem(hDlg, IDC_ENCSETTINGS_BUTTON, SW_HIDE);
  1354. SetDlgItemTextW(hDlg, IDC_ENCSETTINGS_LABEL, LocalisedString(IDS_ENCODER_SETTINGS, NULL, 0));
  1355. wchar_t tmp[128] = {0};
  1356. StringCchPrintfW(tmp, ARRAYSIZE(tmp), LocalisedString(IDS_LAME_ENCODER_VER, NULL, 0), lame_version);
  1357. SetDlgItemTextW(hDlg, IDC_ENCSETTINGS_LAME_VER, tmp);
  1358. ShowWindowDlgItem(hDlg, IDC_ENCSETTINGS_LAME_VER, SW_SHOW);
  1359. } else {
  1360. ShowWindowDlgItem(hDlg, IDC_ENCSETTINGS, SW_HIDE);
  1361. ShowWindowDlgItem(hDlg, IDC_ENCSETTINGS_BUTTON, SW_HIDE);
  1362. SetDlgItemTextW(hDlg, IDC_ENCSETTINGS_LABEL, LocalisedString(IDS_MP3_ENCODING_NOT_AVAILABLE, NULL, 0));
  1363. }
  1364. }
  1365. } else {
  1366. ShowWindowDlgItem(hDlg, IDC_ENCSETTINGS_LAME_VER, SW_HIDE);
  1367. }
  1368. // show / hide the groupbox around the main encoder options
  1369. // which is setup to make it look like it's only around the
  1370. // options available depending upon the mode that is in use
  1371. ShowWindowDlgItem(hDlg, IDC_INFO_FRAME4, !show);
  1372. ShowWindowDlgItem(hDlg, IDC_INFO_FRAME5, show);
  1373. // show / hide the save encoded audio options as applicable
  1374. ShowWindowDlgItem(hDlg, IDC_INFO_FRAME3, show);
  1375. ShowWindowDlgItem(hDlg, IDC_SAVE_ENCODED_AUDIO, show);
  1376. ShowWindowDlgItem(hDlg, IDC_SAVE_ENCODED_AUDIO_EDIT, show);
  1377. ShowWindowDlgItem(hDlg, IDC_SAVE_ENCODED_AUDIO_BROWSE, show);
  1378. }
  1379. void FreeStreamAlbumArt(int Index) {
  1380. if (streamImage[Index] > (ARGB32 *)0 &&
  1381. streamImage[Index] != (ARGB32 *)-1 &&
  1382. WASABI_API_MEMMGR) {
  1383. WASABI_API_MEMMGR->sysFree(streamImage[Index]);
  1384. streamImage[Index] = (ARGB32 *)-1;
  1385. }
  1386. streamLength[Index] = 0;
  1387. }
  1388. // destroy dlg and exit
  1389. int doQuit(void) {
  1390. if (nowPlayingHook) {
  1391. UnhookWindowsHookEx(nowPlayingHook);
  1392. nowPlayingHook = 0;
  1393. }
  1394. if (nowPlayingHook2) {
  1395. UnhookWindowsHookEx(nowPlayingHook2);
  1396. nowPlayingHook2 = 0;
  1397. }
  1398. RemoveSystrayIcon(hMainDLG, SYSTRAY_ICY_ICON);
  1399. GetWindowRect(hMainDLG, &mainrect);
  1400. KillTimer(hMainDLG, wnd[curtab].id);
  1401. KillTimer(hMainDLG, IDD_ENCODER);
  1402. KillTimer(hMainDLG, 666);
  1403. KillTimer(hMainDLG, 1234);
  1404. KillTimer(hMainDLG, 1337);
  1405. KillTimer(hMainDLG, 2234);
  1406. KillTimer(hMainDLG, 2235);
  1407. if (curtab == 1) KillTimer(wnd[curtab].hWnd, out_wnd[curouttab].id);
  1408. if (curtab == 2) KillTimer(wnd[curtab].hWnd, in_wnd[InputDevice].id);
  1409. ini_modified = 1;
  1410. /* Disconnect all outputs */
  1411. int done;
  1412. do {
  1413. done = 1;
  1414. for (int i = 0; i < NUM_OUTPUTS; i++) {
  1415. MY_T_OUTPUT *Out = &Output[i];
  1416. if (Out->Encoder != -1 && Out->Handle != -1) {
  1417. SHOUTCAST_OUTPUT *Enc = &Encoder[Out->Encoder];
  1418. int state = Enc->GetState(Out->Handle);
  1419. if (state != OUT_DISCONNECTED && state != OUT_ERROR) {
  1420. done = 0;
  1421. Enc->DisconnectOutput(Out->Handle);
  1422. } else {
  1423. // shutdown the logging options
  1424. if (Out->Logging) {
  1425. StopLogging(i);
  1426. }
  1427. if (Out->nextTrackLog) {
  1428. StopNextTracks(i);
  1429. }
  1430. if (Out->saveEncoded) {
  1431. StopSaveEncoded(i);
  1432. }
  1433. }
  1434. Enc->Run(OM_OUTPUT | OM_OTHER);
  1435. }
  1436. }
  1437. Sleep(200);
  1438. } while (!done);
  1439. // reset levels if PTT is enabled when we are closing
  1440. if (FadeOut && InputDevice) {
  1441. int micsrc = Input_Device_ID >= 1 ? MIXERLINE_COMPONENTTYPE_SRC_LINE : MIXERLINE_COMPONENTTYPE_SRC_MICROPHONE;
  1442. setlev(micsrc, 0);
  1443. setlev(MIXERLINE_COMPONENTTYPE_SRC_WAVEOUT, MusVol * 10);
  1444. }
  1445. if (hthread) {
  1446. CloseHandle(hthread);
  1447. hthread = NULL;
  1448. }
  1449. if (hthreadout) {
  1450. CloseHandle(hthreadout);
  1451. hthreadout = NULL;
  1452. }
  1453. ReleaseMutex(cf_mutex);
  1454. Soundcard.Close();
  1455. SendMessage(hMainDLG, WM_TIMER, MAKEWPARAM(666,0), 0); // force an INI save
  1456. if (playingImage && WASABI_API_MEMMGR) {
  1457. WASABI_API_MEMMGR->sysFree(playingImage);
  1458. playingImage = 0;
  1459. }
  1460. for (int i = 0; i < NUM_OUTPUTS; i++) {
  1461. FreeStreamAlbumArt(i);
  1462. }
  1463. if (libinst) {
  1464. FreeLibrary(libinst);
  1465. libinst = 0;
  1466. }
  1467. C_ENCODER_FHGAAC::Unload();
  1468. C_ENCODER_AACP::Unload();
  1469. #ifdef USE_OGG
  1470. C_ENCODER_OGG::Unload();
  1471. #endif // USE_OGG
  1472. for (int i = 0; i < num_tabwnds; i++) DestroyWindow(wnd[i].hWnd);
  1473. for (int i = 0; i < num_inwnds; i++) DestroyWindow(in_wnd[i].hWnd);
  1474. for (int i = 0; i < num_outwnds; i++) DestroyWindow(out_wnd[i].hWnd);
  1475. for (int ii = 0; ii < NUM_OUTPUTS; ii++) {
  1476. MY_T_OUTPUT *Out = &Output[ii];
  1477. // removed encoder selection
  1478. if (Out->Encoder != -1) {
  1479. if (Out->Handle != -1) {
  1480. if (WaitForSingleObject(Enc_mutex[Out->Encoder], INFINITE) == WAIT_OBJECT_0) {
  1481. Encoder[Out->Encoder].RemoveOutput(Out->Handle);
  1482. ReleaseMutex(Enc_mutex[Out->Encoder]);
  1483. }
  1484. }
  1485. }
  1486. }
  1487. DestroyWindow(hMainDLG);
  1488. hMainDLG = NULL;
  1489. num_cols = num_outwnds = num_inwnds = num_tabwnds = 0;
  1490. memset(&col, 0, sizeof(col));
  1491. memset(&wnd, 0, sizeof(wnd));
  1492. memset(&out_wnd, 0, sizeof(out_wnd));
  1493. memset(&in_wnd, 0, sizeof(in_wnd));
  1494. memset(&Output, 0, sizeof(Output));
  1495. WASABI_API_LNG_HINST = WASABI_API_ORIG_HINST = 0;
  1496. memset(&lastFile, 0, sizeof(lastFile));
  1497. memset(&lastSec, 0, sizeof(lastSec));
  1498. memset(&lastFile, 0, sizeof(lastFile));
  1499. memset(&lastMode, -1, sizeof(lastMode));
  1500. memset(&lastEnable, 0, sizeof(lastEnable));
  1501. memset(&buttonWnd, 0, sizeof(buttonWnd));
  1502. memset(&tabWnd, 0, sizeof(tabWnd));
  1503. memset(&outTabWnd, 0, sizeof(outTabWnd));
  1504. memset(&streamLength, 0, sizeof(streamLength));
  1505. memset(&secChanged, 0, sizeof(secChanged));
  1506. playingImage_w = playingImage_h = playingLength = playingType;
  1507. if (boldFont) {
  1508. DeleteObject(boldFont);
  1509. boldFont = NULL;
  1510. }
  1511. normalFont = NULL;
  1512. ServiceRelease(WASABI_API_SVC, AGAVE_API_CONFIG, AgaveConfigGUID);
  1513. ServiceRelease(WASABI_API_SVC, WASABI_API_LNG, languageApiGUID);
  1514. ServiceRelease(WASABI_API_SVC, WASABI_API_MEMMGR, memMgrApiServiceGuid);
  1515. ServiceRelease(WASABI_API_SVC, AGAVE_API_ALBUMART, albumArtGUID);
  1516. ServiceRelease(WASABI_API_SVC, WASABI_API_QUEUEMGR, QueueManagerApiGUID);
  1517. ServiceRelease(WASABI_API_SVC, WASABI_API_EXPLORERFINDFILE,ExplorerFindFileApiGUID);
  1518. ServiceRelease(WASABI_API_SVC, WAC_API_DOWNLOADMANAGER, DownloadManagerGUID);
  1519. WASABI_API_SVC = NULL;
  1520. return 1;
  1521. }
  1522. void SetBoldDialogItemFont(HWND hwndControl) {
  1523. if (!boldFont) {
  1524. HFONT hFont = (HFONT)SendMessageW(hMainDLG, WM_GETFONT, 0, 0);
  1525. LOGFONTW lf = {0};
  1526. GetObjectW(hFont, sizeof(LOGFONTW), &lf);
  1527. lf.lfWeight = FW_BOLD;
  1528. boldFont = CreateFontIndirectW(&lf);
  1529. }
  1530. if (boldFont) {
  1531. SendMessageW(hwndControl, WM_SETFONT, (WPARAM)boldFont, MAKELPARAM(1,0));
  1532. }
  1533. }
  1534. LRESULT WINAPI headerProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) {
  1535. if (uMsg == WM_SETCURSOR) {
  1536. return TRUE;
  1537. }
  1538. return CallWindowProcW(prevHeaderProc, hWnd, uMsg, wParam, lParam);
  1539. }
  1540. LRESULT WINAPI listViewProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) {
  1541. switch (uMsg) {
  1542. case WM_COMMAND:
  1543. switch (LOWORD(wParam)) {
  1544. case IDC_STREAM_1:
  1545. case IDC_STREAM_2:
  1546. case IDC_STREAM_3:
  1547. case IDC_STREAM_4:
  1548. case IDC_STREAM_5:
  1549. {
  1550. int oldCurSelPos = Connection_CurSelPos;
  1551. Connection_CurSelPos = (LOWORD(wParam) - IDC_STREAM_1);
  1552. ListView_SetItemState(hWnd, Connection_CurSelPos, LVIS_SELECTED | LVIS_FOCUSED, LVIS_SELECTED | LVIS_FOCUSED);
  1553. SetFocus(hWnd);
  1554. SendMessage(wnd[1].hWnd, WM_COMMAND, MAKEWPARAM(IDC_CONNECT, BN_CLICKED), (LPARAM)GetDlgItem(wnd[1].hWnd, IDC_CONNECT));
  1555. Connection_CurSelPos = oldCurSelPos;
  1556. }
  1557. return 0;
  1558. }
  1559. break;
  1560. case WM_NOTIFY:
  1561. if(((LPNMHDR)lParam)->code == HDN_BEGINTRACKW ||
  1562. ((LPNMHDR)lParam)->code == HDN_ITEMCHANGINGW) {
  1563. return TRUE;
  1564. }
  1565. break;
  1566. }
  1567. return CallWindowProcW(prevListViewProc, hWnd, uMsg, wParam, lParam);
  1568. }
  1569. void SetTabErrorText(HWND hwnd, int index, int current, LPRECT r, bool update = false) {
  1570. HDC hDC = GetDC(hwnd);
  1571. if (!normalFont) {
  1572. normalFont = (HFONT)SendMessageW(hMainDLG, WM_GETFONT, 0, 0);
  1573. }
  1574. HFONT hOldFont = (HFONT)SelectObject(hDC, normalFont);
  1575. int oldTextColor = SetTextColor(hDC, (!update ? RGB(255,0,0) : RGB(0,0,255)));
  1576. int oldBkMode = SetBkMode(hDC, TRANSPARENT);
  1577. wchar_t buf[128] = {0};
  1578. TCITEMW pitem = {0};
  1579. pitem.mask = TCIF_TEXT;
  1580. pitem.pszText = buf;
  1581. pitem.cchTextMax = ARRAYSIZE(buf);
  1582. SendMessageW(hwnd, TCM_GETITEMW, index, (LPARAM)&pitem);
  1583. r->top += (current ? 1 : 3);
  1584. r->left += 6;
  1585. // if themeing is enabled then we need to paint the background to avoid the font going weird / double-bold like
  1586. // and to ensure we're correct, am taking a 1px sliver and stretching it across the area before drawing the text
  1587. if (isthemethere) {
  1588. StretchBlt(hDC, r->left, r->top + 1, r->right - r->left - 3, r->bottom - r->top - 3, hDC, r->left - 4, r->top + 1, 1, r->bottom - r->top - 3, SRCCOPY);
  1589. }
  1590. DrawTextW(hDC, pitem.pszText, wcslen(pitem.pszText), r, DT_SINGLELINE);
  1591. SetTextColor(hDC, oldTextColor);
  1592. SetBkMode(hDC, oldBkMode);
  1593. SelectObject(hDC, hOldFont);
  1594. ReleaseDC(hwnd, hDC);
  1595. }
  1596. LRESULT WINAPI tabWndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) {
  1597. LRESULT ret = CallWindowProcW(prevTabWndProc, hWnd, uMsg, wParam, lParam);
  1598. if (uMsg == WM_PAINT) {
  1599. RECT r = {0};
  1600. int item = ListView_GetNextItem(GetDlgItem(wnd[0].hWnd, IDC_OUTPUTSTATUS), -1, LVNI_SELECTED);
  1601. if ((curtab == 1 ?
  1602. (lastMode[Connection_CurSelPos] >= 3 && lastMode[Connection_CurSelPos] <= 6) :
  1603. (lastMode[item] >= 3 && lastMode[item] <= 6)
  1604. ) && TabCtrl_GetItemRect(hWnd, 1, &r)) {
  1605. SetTabErrorText(hWnd, 1, (curtab == 1), &r);
  1606. }
  1607. // show the update flag on things!
  1608. if (updateStr && updateStr[0]) {
  1609. RECT r = {0};
  1610. TabCtrl_GetItemRect(tabWnd, 3, &r);
  1611. SetTabErrorText(tabWnd, 3, (curtab == 3), &r, TRUE);
  1612. }
  1613. }
  1614. return ret;
  1615. }
  1616. LRESULT WINAPI outTabWndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) {
  1617. LRESULT ret = CallWindowProcW(prevOutTabWndProc, hWnd, uMsg, wParam, lParam);
  1618. if (uMsg == WM_PAINT) {
  1619. for (int i = 0; i < NUM_OUTPUTS; i++) {
  1620. RECT r = {0};
  1621. int index[] = {0, 0, 1, 2};
  1622. if ((lastMode[i] >= 3 && lastMode[i] <= 6) && (i == Connection_CurSelPos) && TabCtrl_GetItemRect(hWnd, index[(lastMode[i] - 3)], &r)) {
  1623. SetTabErrorText(hWnd, index[(lastMode[i] - 3)], (curouttab == index[(lastMode[i] - 3)]), &r);
  1624. }
  1625. }
  1626. }
  1627. return ret;
  1628. }
  1629. LRESULT WINAPI buttonProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) {
  1630. int ret;
  1631. switch (uMsg) {
  1632. case WM_LBUTTONDOWN:
  1633. ret = CallWindowProcW(prevButtonProc, hWnd, uMsg, wParam, lParam);
  1634. if (SendDlgItemMessage(GetParent(hWnd), IDC_LOCK, BM_GETSTATE, 0, 0) != BST_CHECKED) {
  1635. blockmousemove = 1;
  1636. KillTimer(hMainDLG, 2234);
  1637. KillTimer(hMainDLG, 2235);
  1638. if ((MicFadeStartTime != 0 || FadeStartTime != 0) && FadeOut != 1) {
  1639. clock_t myTime = clock();
  1640. if (FadeStartTime != 0) FadeStartTime = myTime - ((FadeTime * 100)-(myTime - FadeStartTime));
  1641. if (MicFadeStartTime != 0) MicFadeStartTime = myTime - ((MicFadeTime * 100)-(myTime - MicFadeStartTime));
  1642. }
  1643. FadeOut = 1;
  1644. SetTimer(hMainDLG, 2234, 10, NULL); // fade out
  1645. SetTimer(hMainDLG, 2235, 10, NULL); // fade out
  1646. //if (FadeOut) do_capture();
  1647. #ifdef CAPTURE_TESTING
  1648. if (FadeOut) {
  1649. if (!pPlayer) {
  1650. pPlayer = new Player(hMainDLG);
  1651. }
  1652. if (!pCallbacks) {
  1653. pCallbacks = new CPlayerCallbacks();
  1654. }
  1655. pPlayer->SetPlayerCallbacks(pCallbacks);
  1656. pPlayer->RefreshDeviceList(eRender);
  1657. pPlayer->RefreshDeviceList(eCapture);
  1658. pPlayer->SelectDefaultDevice(eRender, eConsole);
  1659. pPlayer->SelectDefaultDevice(eCapture, eConsole);
  1660. pPlayer->SelectDeviceFromList(eCapture, 0);
  1661. //pPlayer->SelectDeviceFromList(eRender, 2);
  1662. if (pPlayer->Play(eCaptureEndpoint) == FALSE) {
  1663. return TRUE;
  1664. }
  1665. }
  1666. #endif
  1667. } else {
  1668. SendMessage(hWnd, BM_SETSTATE, TRUE, 0);
  1669. ret = 0;
  1670. }
  1671. return ret;
  1672. case WM_MOUSEMOVE:
  1673. if (blockmousemove) return 0;
  1674. break;
  1675. case WM_LBUTTONUP:
  1676. ret = CallWindowProcW(prevButtonProc, hWnd, uMsg, wParam, lParam);
  1677. if (SendDlgItemMessage(GetParent(hWnd), IDC_LOCK, BM_GETSTATE, 0, 0) != BST_CHECKED) {
  1678. blockmousemove = 0;
  1679. KillTimer(hMainDLG, 2234);
  1680. KillTimer(hMainDLG, 2235);
  1681. if ((MicFadeStartTime != 0 || FadeStartTime != 0) && FadeOut != 0) {
  1682. clock_t myTime = clock();
  1683. if (FadeStartTime != 0) FadeStartTime = myTime - ((FadeTime * 100)-(myTime - FadeStartTime));
  1684. if (MicFadeStartTime != 0) MicFadeStartTime = myTime - ((MicFadeTime * 100)-(myTime - MicFadeStartTime));
  1685. }
  1686. FadeOut = 0;
  1687. SetTimer(hMainDLG, 2234, 10, NULL); // fade in
  1688. SetTimer(hMainDLG, 2235, 10, NULL); // fade in
  1689. } else {
  1690. SendMessage(hWnd, BM_SETSTATE, TRUE, 0);
  1691. ret = 0;
  1692. }
  1693. return ret;
  1694. }
  1695. return CallWindowProcW(prevButtonProc, hWnd, uMsg, wParam, lParam);
  1696. }
  1697. int CALLBACK EncFunc(HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam) {
  1698. switch (uMsg) {
  1699. case WM_INITDIALOG:
  1700. {
  1701. // doing this to get the button + combobox to appear as the same size when scrolling through them all
  1702. RECT r;
  1703. GetClientRect(GetDlgItem(hDlg, IDC_ENCSETTINGS), &r);
  1704. MapWindowPoints(GetDlgItem(hDlg, IDC_ENCSETTINGS), hDlg, (LPPOINT)&r,2);
  1705. InflateRect(&r, 1, 1);
  1706. SetWindowPos(GetDlgItem(hDlg, IDC_ENCSETTINGS_BUTTON), 0, r.left, r.top, r.right-r.left, r.bottom-r.top, SWP_NOZORDER|SWP_NOACTIVATE);
  1707. }
  1708. break;
  1709. case WM_COMMAND:
  1710. {
  1711. switch (LOWORD(wParam)) {
  1712. case IDC_ENCODERLIST:
  1713. {
  1714. if (HIWORD(wParam) == LBN_SELCHANGE) {
  1715. MY_T_OUTPUT *Out = &Output[Connection_CurSelPos];
  1716. Encoder_CurSelPos = Out->Encoder;
  1717. if (WaitForSingleObject(Enc_mutex[Encoder_CurSelPos], INFINITE) == WAIT_OBJECT_0) {
  1718. C_ENCODER *Enc = Encoder[Encoder_CurSelPos].GetEncoder();
  1719. HWND e = hDlg;
  1720. SendDlgItemMessage(e, IDC_ENCTYPE, CB_RESETCONTENT, 0, 0);
  1721. int item = SendDlgItemMessageW(e, IDC_ENCTYPE, CB_ADDSTRING, 0, (LPARAM) LocalisedString(IDS_NONE, NULL, 0));
  1722. SendDlgItemMessage(e, IDC_ENCTYPE, CB_SETITEMDATA, item, (LPARAM)"None");
  1723. item = SendDlgItemMessageW(e, IDC_ENCTYPE, CB_ADDSTRING, 0, (LPARAM) LocalisedString(IDS_MP3_ENCODER, NULL, 0));
  1724. SendDlgItemMessage(e, IDC_ENCTYPE, CB_SETITEMDATA, item, (LPARAM)"MP3 Encoder");
  1725. if (C_ENCODER_FHGAAC::isPresent(module.hwndParent)) {
  1726. item = SendDlgItemMessageW(e, IDC_ENCTYPE, CB_ADDSTRING, 0, (LPARAM) LocalisedString(IDS_FHGAAC_ENCODER, NULL, 0));
  1727. SendDlgItemMessage(e, IDC_ENCTYPE, CB_SETITEMDATA, item, (LPARAM)"Fraunhofer Encoder");
  1728. } else if (C_ENCODER_AACP::isPresent(module.hwndParent)) {
  1729. item = SendDlgItemMessageW(e, IDC_ENCTYPE, CB_ADDSTRING, 0, (LPARAM) LocalisedString(IDS_AACP_ENCODER, NULL, 0));
  1730. SendDlgItemMessage(e, IDC_ENCTYPE, CB_SETITEMDATA, item, (LPARAM)"AAC+ Encoder");
  1731. }
  1732. #ifdef USE_OGG
  1733. if (C_ENCODER_OGG::isPresent(module.hwndParent)) {
  1734. // TODO
  1735. item = SendDlgItemMessageW(e, IDC_ENCTYPE, CB_ADDSTRING, 0, (LPARAM) L"OGG Vorbis Encoder"/*LocalisedString(IDS_OGG_ENCODER, NULL, 0)*/);
  1736. SendDlgItemMessage(e, IDC_ENCTYPE, CB_SETITEMDATA, item, (LPARAM)"OGG Vorbis Encoder");
  1737. }
  1738. #endif // USE_OGG
  1739. SendDlgItemMessage(e, IDC_ENCSETTINGS, CB_RESETCONTENT, 0, 0);
  1740. SetEncoderPanelMode(e, Enc);
  1741. int attribnum = 0, typeval = 0;
  1742. if (Enc) {
  1743. int i;
  1744. for (int i = 0; i < NUM_ENCODERS; i++) {
  1745. char* encoder = (char*)SendDlgItemMessage(e, IDC_ENCTYPE, CB_GETITEMDATA, i, 0);
  1746. if (!strcmp(Enc->GetName(), encoder)) {
  1747. typeval = i;
  1748. break;
  1749. }
  1750. }
  1751. int infosize = sizeof (T_EncoderIOVals);
  1752. T_ENCODER_MP3_INFO *EncInfo = (T_ENCODER_MP3_INFO *) Enc->GetExtInfo(&infosize);
  1753. for (i = Enc->GetNumAttribs() - 1; i >= 0; i--) {
  1754. T_ATTRIB attrib;
  1755. Enc->EnumAttrib(i, &attrib);
  1756. SendDlgItemMessage(e, IDC_ENCSETTINGS, CB_INSERTSTRING, 0, (LPARAM) attrib.Text);
  1757. T_ENCODER_MP3_INFO *OutVal = (T_ENCODER_MP3_INFO *) attrib.OutputVals;
  1758. if (OutVal && EncInfo && infosize) {
  1759. T_ENCODER_MP3_INFO *EncSettings = (T_ENCODER_MP3_INFO *) EncInfo;
  1760. if(OutVal->output_bitRate == EncSettings->output_bitRate &&
  1761. OutVal->output_sampleRate == EncSettings->output_sampleRate &&
  1762. OutVal->output_numChannels == EncSettings->output_numChannels) {
  1763. attribnum = i;
  1764. }
  1765. }
  1766. }
  1767. } else {
  1768. SendDlgItemMessageW(e, IDC_ENCSETTINGS, CB_ADDSTRING, 0, (LPARAM) LocalisedString(IDS_NONE, NULL, 0));
  1769. ShowWindowDlgItem(e, IDC_ENCSETTINGS, SW_HIDE);
  1770. ShowWindowDlgItem(e, IDC_ENCSETTINGS_BUTTON, SW_HIDE);
  1771. SetDlgItemTextW(e, IDC_ENCSETTINGS_LABEL, LocalisedString(IDS_NO_ENCODER_SELECTED, NULL, 0));
  1772. }
  1773. SendDlgItemMessage(e, IDC_ENCSETTINGS, CB_SETCURSEL, attribnum, 0);
  1774. SendDlgItemMessage(e, IDC_ENCTYPE, CB_SETCURSEL, typeval, 0);
  1775. ReleaseMutex(Enc_mutex[Encoder_CurSelPos]);
  1776. ini_modified = 1;
  1777. SendMessage(hDlg, WM_COMMAND, MAKEWPARAM(IDC_ENCSETTINGS, CBN_SELCHANGE), (LPARAM) GetDlgItem(hDlg, IDC_ENCSETTINGS));
  1778. }
  1779. }
  1780. }
  1781. break;
  1782. case IDC_ENCTYPE:
  1783. {
  1784. if (HIWORD(wParam) == CBN_SELCHANGE) {
  1785. int typenum = SendMessage((HWND) lParam, CB_GETCURSEL, 0, 0);
  1786. // check to see if this is the same encoder as last time as
  1787. // there's no need to update it if there hasn't been a change
  1788. // so selecting the same encoder won't cause a settings reset
  1789. if (typenum && typenum == Enc_LastType[Encoder_CurSelPos]) break;
  1790. else Enc_LastType[Encoder_CurSelPos] = typenum;
  1791. char* typestr = (char*)SendMessage((HWND) lParam, CB_GETITEMDATA, typenum, 0);
  1792. if (WaitForSingleObject(Enc_mutex[Encoder_CurSelPos], INFINITE) == WAIT_OBJECT_0) {
  1793. if (!strcmpi("MP3 Encoder", typestr)) {
  1794. //lame setup
  1795. Encoder[Encoder_CurSelPos].SetLame(init, params, encode, finish);
  1796. Encoder[Encoder_CurSelPos].SetEncoder(new C_ENCODER_MP3(init, params, encode, finish), 1);
  1797. C_ENCODER *Enc = Encoder[Encoder_CurSelPos].GetEncoder();
  1798. if (Enc) {
  1799. if (strcmpi(Enc->GetName(), "MP3 Encoder") == 0) {
  1800. T_ENCODER_MP3_INFO EncSettings;
  1801. int infosize = sizeof (EncSettings);
  1802. T_ENCODER_MP3_INFO *encset = (T_ENCODER_MP3_INFO *) Enc->GetExtInfo(&infosize);
  1803. if (encset && infosize)
  1804. memcpy(&EncSettings, encset, infosize);
  1805. EncSettings.input_numChannels = (InputDevice == 0 ? InputConfig.nch : LineInputAttribs[Input_CurSelPos].nch);
  1806. EncSettings.input_sampleRate = (InputDevice == 0 ? InputConfig.srate : LineInputAttribs[Input_CurSelPos].srate);
  1807. EncSettings.output_bitRate = MP3_DEFAULT_OUTPUTBITRATE;
  1808. EncSettings.output_sampleRate = MP3_DEFAULT_OUTPUTSAMPLERATE;
  1809. EncSettings.output_numChannels = MP3_DEFAULT_OUTPUTNUMCHANNELS;
  1810. Enc->ChangeSettings(&EncSettings);
  1811. }
  1812. }
  1813. } else if (!strcmpi("Fraunhofer Encoder", typestr)) { // FHG AAC
  1814. Encoder[Encoder_CurSelPos].SetEncoder(new C_ENCODER_FHGAAC(module.hwndParent), 1);
  1815. C_ENCODER *Enc = Encoder[Encoder_CurSelPos].GetEncoder();
  1816. if (Enc) {
  1817. T_ENCODER_FHGAAC_INFO EncSettings;
  1818. int infosize = sizeof (EncSettings);
  1819. T_ENCODER_FHGAAC_INFO *encset = (T_ENCODER_FHGAAC_INFO *) Enc->GetExtInfo(&infosize);
  1820. if (encset && infosize) memcpy(&EncSettings, encset, infosize);
  1821. EncSettings.input_numChannels = (InputDevice == 0 ? InputConfig.nch : LineInputAttribs[Input_CurSelPos].nch);
  1822. EncSettings.input_sampleRate = (InputDevice == 0 ? InputConfig.srate : LineInputAttribs[Input_CurSelPos].srate);
  1823. Enc->ChangeSettings(&EncSettings);
  1824. }
  1825. } else if (!strcmpi("AAC+ Encoder", typestr)) { //AAC+
  1826. Encoder[Encoder_CurSelPos].SetEncoder(new C_ENCODER_AACP(module.hwndParent), 1);
  1827. C_ENCODER *Enc = Encoder[Encoder_CurSelPos].GetEncoder();
  1828. if (Enc) {
  1829. T_ENCODER_AACP_INFO EncSettings;
  1830. int infosize = sizeof (EncSettings);
  1831. T_ENCODER_AACP_INFO *encset = (T_ENCODER_AACP_INFO *) Enc->GetExtInfo(&infosize);
  1832. if (encset && infosize) memcpy(&EncSettings, encset, infosize);
  1833. EncSettings.input_numChannels = (InputDevice == 0 ? InputConfig.nch : LineInputAttribs[Input_CurSelPos].nch);
  1834. EncSettings.input_sampleRate = (InputDevice == 0 ? InputConfig.srate : LineInputAttribs[Input_CurSelPos].srate);
  1835. Enc->ChangeSettings(&EncSettings);
  1836. }
  1837. }
  1838. #ifdef USE_OGG
  1839. else if (!strcmpi("OGG Vorbis Encoder", typestr)) { //OGG
  1840. Encoder[Encoder_CurSelPos].SetEncoder(new C_ENCODER_OGG(module.hwndParent), 1);
  1841. C_ENCODER *Enc = Encoder[Encoder_CurSelPos].GetEncoder();
  1842. if (Enc) {
  1843. T_ENCODER_OGG_INFO EncSettings;
  1844. int infosize = sizeof (EncSettings);
  1845. T_ENCODER_OGG_INFO *encset = (T_ENCODER_OGG_INFO *) Enc->GetExtInfo(&infosize);
  1846. if (encset && infosize) memcpy(&EncSettings, encset, infosize);
  1847. EncSettings.input_numChannels = (InputDevice == 0 ? InputConfig.nch : LineInputAttribs[Input_CurSelPos].nch);
  1848. EncSettings.input_sampleRate = (InputDevice == 0 ? InputConfig.srate : LineInputAttribs[Input_CurSelPos].srate);
  1849. Enc->ChangeSettings(&EncSettings);
  1850. }
  1851. }
  1852. #endif // USE_OGG
  1853. else {
  1854. int i;
  1855. for (i = 0; i < NUM_OUTPUTS; i++) {
  1856. MY_T_OUTPUT *Out = &Output[i];
  1857. if (Out->Encoder == Encoder_CurSelPos && Out->Handle != -1) Encoder[Encoder_CurSelPos].DisconnectOutput(Out->Handle);
  1858. }
  1859. Encoder[Encoder_CurSelPos].SetEncoder(NULL);
  1860. }
  1861. // if we can re-map the extension then we do so against the encoder selected
  1862. // which will override what was manually set but this ensures it is correct!
  1863. MY_T_OUTPUT *Out = &Output[Connection_CurSelPos];
  1864. if (Out->saveEncodedPath[0] && typenum != 0) {
  1865. PathRemoveExtensionW(Out->saveEncodedPath);
  1866. PathAddExtensionW(Out->saveEncodedPath,
  1867. (Enc_LastType[Connection_CurSelPos] != 0 ?
  1868. (!strcmp(Encoder[Out->Encoder].GetEncoder()->GetContentType(),"audio/mpeg") ? L".mp3" :
  1869. (!strcmp(Encoder[Out->Encoder].GetEncoder()->GetContentType(),"audio/ogg") ? L".ogg" : L".aac")) : L""));
  1870. // update things as the filename was changed
  1871. SetDlgItemTextW(out_wnd[2].hWnd, IDC_SAVE_ENCODED_AUDIO_EDIT, Out->saveEncodedPath);
  1872. if (Out->saveEncoded) {
  1873. StopSaveEncoded(Connection_CurSelPos);
  1874. StartSaveEncoded(Connection_CurSelPos, Out->saveEncodedPath);
  1875. }
  1876. }
  1877. SetEncoderPanelMode(hDlg, Encoder[Encoder_CurSelPos].GetEncoder());
  1878. ReleaseMutex(Enc_mutex[Encoder_CurSelPos]);
  1879. ini_modified = 1;
  1880. SendMessage(hDlg, WM_COMMAND, MAKEWPARAM(IDC_ENCODERLIST, LBN_SELCHANGE), (LPARAM) GetDlgItem(hDlg, IDC_ENCODERLIST));
  1881. }
  1882. }
  1883. }
  1884. break;
  1885. case IDC_ENCSETTINGS_BUTTON:
  1886. {
  1887. C_ENCODER *Enc = Encoder[Encoder_CurSelPos].GetEncoder();
  1888. if (Enc) if (Enc->UseNsvConfig()) {
  1889. ((C_ENCODER_NSV*) Enc)->Configure(hDlg, module.hDllInstance);
  1890. if (WaitForSingleObject(Enc_mutex[Encoder_CurSelPos], INFINITE) == WAIT_OBJECT_0) {
  1891. ini_modified = 1;
  1892. for (int i = 0; i < NUM_OUTPUTS; i++) {
  1893. MY_T_OUTPUT *Out = &Output[i];
  1894. if (Out->Encoder == Encoder_CurSelPos && Out->Handle != -1) {
  1895. Encoder[Encoder_CurSelPos].DisconnectOutput(Out->Handle, 1, 5);
  1896. }
  1897. }
  1898. ReleaseMutex(Enc_mutex[Encoder_CurSelPos]);
  1899. }
  1900. }
  1901. SetEncoderPanelMode(hDlg, Enc);
  1902. }
  1903. break;
  1904. case IDC_ENCSETTINGS:
  1905. {
  1906. if (HIWORD(wParam) == CBN_SELCHANGE) {
  1907. T_ATTRIB attrib;
  1908. int attribnum = SendMessage((HWND) lParam, CB_GETCURSEL, 0, 0);
  1909. if (WaitForSingleObject(Enc_mutex[Encoder_CurSelPos], INFINITE) == WAIT_OBJECT_0) {
  1910. C_ENCODER *Enc = Encoder[Encoder_CurSelPos].GetEncoder();
  1911. if (Enc) {
  1912. int i;
  1913. if (attribnum < 0 || attribnum >= Enc->GetNumAttribs()) attribnum = 0;
  1914. int oldattrib = -1;
  1915. int infosize = sizeof (T_EncoderIOVals);
  1916. T_EncoderIOVals *EncInfo = (T_EncoderIOVals *) Enc->GetExtInfo(&infosize);
  1917. for (i = Enc->GetNumAttribs() - 1; i >= 0 && oldattrib == -1; i--) {
  1918. Enc->EnumAttrib(i, &attrib);
  1919. if (attrib.OutputVals && EncInfo && infosize) {
  1920. T_ENCODER_MP3_INFO *EncSettings = (T_ENCODER_MP3_INFO *) attrib.OutputVals;
  1921. T_ENCODER_MP3_INFO *EncSettings2 = (T_ENCODER_MP3_INFO *) EncInfo;
  1922. //if (memcmp(attrib.OutputVals, EncInfo, infosize) == 0) oldattrib = i;
  1923. if(EncSettings2->output_bitRate == EncSettings->output_bitRate &&
  1924. EncSettings2->output_sampleRate == EncSettings->output_sampleRate &&
  1925. EncSettings2->output_numChannels == EncSettings->output_numChannels) {
  1926. oldattrib = i;
  1927. }
  1928. }
  1929. }
  1930. if (attribnum != oldattrib) {
  1931. if (Enc->EnumAttrib(attribnum, &attrib)) {
  1932. // we make sure that we set the input channels and samplerate to
  1933. // that of the mode being used instead of the default values as
  1934. // this allows us to get things to work correctly (done in 2.3.2)
  1935. T_ENCODER_MP3_INFO *EncSettings = (T_ENCODER_MP3_INFO *) attrib.OutputVals;
  1936. if(InputDevice == 1) {
  1937. EncSettings->input_numChannels = (InputDevice == 0 ? InputConfig.nch : LineInputAttribs[Input_CurSelPos].nch);
  1938. EncSettings->input_sampleRate = (InputDevice == 0 ? InputConfig.srate : LineInputAttribs[Input_CurSelPos].srate);
  1939. }
  1940. Enc->ChangeSettings(EncSettings);
  1941. ini_modified = 1;
  1942. for (i = 0; i < NUM_OUTPUTS; i++) {
  1943. MY_T_OUTPUT *Out = &Output[i];
  1944. if (Out->Encoder == Encoder_CurSelPos && Out->Handle != -1) {
  1945. Encoder[Encoder_CurSelPos].DisconnectOutput(Out->Handle, 1, 5);
  1946. }
  1947. }
  1948. }
  1949. }
  1950. }
  1951. ReleaseMutex(Enc_mutex[Encoder_CurSelPos]);
  1952. }
  1953. }
  1954. }
  1955. break;
  1956. }//switch
  1957. }
  1958. break;
  1959. }// umsg
  1960. return CallWindowProcW((WNDPROC)DialogFunc, hDlg, uMsg, wParam, lParam);
  1961. }
  1962. /* Connection Page callback */
  1963. INT_PTR CALLBACK ConnectionFunc(HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam) {
  1964. switch (uMsg) {
  1965. case WM_INITDIALOG:
  1966. {
  1967. switch (lParam) {
  1968. case IDD_CONNECTION:
  1969. {
  1970. int i;
  1971. wchar_t temp[128];
  1972. SendDlgItemMessage(hDlg, IDC_OUTPUTLIST, LB_RESETCONTENT, 0, 0);
  1973. for (i = 0; i < NUM_OUTPUTS; i++) {
  1974. T_OUTPUT_CONFIG *Out = &Output[i].Config;
  1975. SendDlgItemMessageW(hDlg, IDC_OUTPUTLIST, LB_ADDSTRING, 0, (LPARAM) Out->DisplayName);
  1976. }
  1977. SendDlgItemMessage(hDlg, IDC_OUTPUTLIST, LB_SETCURSEL, Connection_CurSelPos, 0);
  1978. num_outwnds = 0;
  1979. SendDlgItemMessage(hDlg, IDC_CONTAB, TCM_DELETEALLITEMS, 0, 0);
  1980. AddOutTab(IDD_PANEL_LOGIN, LocalisedString(IDS_PANEL_LOGIN, temp, 128), hDlg, DialogFunc, IDC_CONTAB, IDC_PANELRECT_C, 0);
  1981. AddOutTab(IDD_PANEL_DIRECTORY, LocalisedString(IDS_PANEL_DIRECTORY, temp, 128), hDlg, DialogFunc, IDC_CONTAB, IDC_PANELRECT_C, 0);
  1982. AddOutTab(IDD_ENCODER, LocalisedString(IDS_PANEL_ENCODERS, temp, 128), hDlg, EncFunc, IDC_CONTAB, IDC_PANELRECT_C, 0);
  1983. AddOutTab(IDD_PANEL_TITLE, LocalisedString(IDS_PANEL_TITLES, temp, 128), hDlg, DialogFunc, IDC_CONTAB, IDC_PANELRECT_C, 0);
  1984. AddOutTab(IDD_ARTWORK, LocalisedString(IDS_PANEL_ART, temp, 128), hDlg, DialogFunc, IDC_CONTAB, IDC_PANELRECT_C, 0);
  1985. AddOutTab(IDD_LOGGING, LocalisedString(IDS_PANEL_LOGGING, temp, 128), hDlg, DialogFunc, IDC_CONTAB, IDC_PANELRECT_C, 0);
  1986. SetOutTab(curouttab, hDlg, IDC_CONTAB);
  1987. SendMessage(hDlg, WM_COMMAND, MAKEWPARAM(IDC_OUTPUTLIST, LBN_SELCHANGE), (LPARAM) GetDlgItem(hDlg, IDC_OUTPUTLIST));
  1988. SendDlgItemMessage(wnd[1].hWnd, IDC_AUTOCONNECT, BM_SETCHECK,Output[Connection_CurSelPos].AutoConnect ? BST_CHECKED : BST_UNCHECKED, 0);
  1989. }
  1990. break;
  1991. }//lparam
  1992. }
  1993. return 0;
  1994. }//uMsg
  1995. return CallWindowProcW((WNDPROC)DialogFunc, hDlg, uMsg, wParam, lParam);
  1996. }
  1997. void ShowUpdateMessage(HWND hDlg)
  1998. {
  1999. bool update = (updateStr && updateStr[0]);
  2000. if (IsWindow(hDlg))
  2001. {
  2002. HWND control = GetDlgItem(hDlg, IDC_UPDATE_HEADER);
  2003. if (update)
  2004. {
  2005. wchar_t message[128] = {0};
  2006. StringCchPrintfW(message, ARRAYSIZE(message), WASABI_API_LNGSTRINGW(IDS_UPDATE_HEADER), updateStr);
  2007. SetWindowTextW(control, message);
  2008. SetBoldDialogItemFont(control);
  2009. }
  2010. else
  2011. {
  2012. SetWindowTextW(control, WASABI_API_LNGSTRINGW(IDS_UPDATE));
  2013. SendMessageW(control, WM_SETFONT, SendMessageW(hMainDLG, WM_GETFONT, 0, 0), 0);
  2014. InvalidateRect(hDlg, 0, TRUE);
  2015. }
  2016. ShowWindowDlgItem(hDlg, IDC_STATIC_UPDATE, update);
  2017. ShowWindowDlgItem(hDlg, IDC_UPDATELINK, update);
  2018. }
  2019. SetWindowTextW(hMainDLG, WASABI_API_LNGSTRINGW((update ? IDS_UPDATE_TITLE : IDS_MODULE_NAME)));
  2020. if (IsWindow(tabWnd)) {
  2021. RECT r = {0};
  2022. TabCtrl_GetItemRect(tabWnd, 3, &r);
  2023. InvalidateRect(tabWnd, &r, 0);
  2024. }
  2025. }
  2026. class VersionCheckCallback : public ifc_downloadManagerCallback
  2027. {
  2028. public:
  2029. void OnInit( DownloadToken token )
  2030. {
  2031. api_httpreceiver *http = WAC_API_DOWNLOADMANAGER->GetReceiver( token );
  2032. if ( http )
  2033. {
  2034. http->AllowCompression();
  2035. http->addheader( "Accept: */*" );
  2036. }
  2037. }
  2038. void OnFinish( DownloadToken token )
  2039. {
  2040. api_httpreceiver *http = WAC_API_DOWNLOADMANAGER->GetReceiver( token );
  2041. if ( http && http->getreplycode() == 200 )
  2042. {
  2043. char *buf = 0;
  2044. size_t size = 0;
  2045. if ( WAC_API_DOWNLOADMANAGER->GetBuffer( token, (void **)&buf, &size ) == 0 && size > 0 )
  2046. {
  2047. buf[ size - 1 ] = 0;
  2048. char *p = buf;
  2049. while ( size && ( *p == ' ' || *p == '\t' || *p == '\r' || *p == '\n' ) )
  2050. {
  2051. p++;
  2052. size--;
  2053. }
  2054. // e.g. dsp_sc,2.3.4.210,http://download.nullsoft.com/shoutcast/tools/shoutcast-dsp-2-3-4-windows.exe
  2055. if ( p && *p )
  2056. {
  2057. char *tok = strtok( p, "," );
  2058. if ( tok )
  2059. {
  2060. if ( !strncmp( tok, "dsp_sc", 6 ) )
  2061. {
  2062. tok = strtok( NULL, "," );
  2063. if ( tok )
  2064. {
  2065. bool needsUpdating = CompareVersions( tok );
  2066. lstrcpyn( updateStr, ( needsUpdating ? tok : "" ), ARRAYSIZE( updateStr ) );
  2067. WritePrivateProfileString( APP_Name, "Update", ( needsUpdating ? updateStr : 0 ), IniName );
  2068. ShowUpdateMessage( updateWnd );
  2069. if ( !needsUpdating )
  2070. {
  2071. ShowWindowDlgItem( updateWnd, IDC_STATIC_UPDATE, TRUE );
  2072. }
  2073. SetDlgItemTextW( updateWnd, IDC_STATIC_UPDATE, WASABI_API_LNGSTRINGW( ( needsUpdating ? IDS_HAS_NEW_UPDATE : IDS_NO_NEW_UPDATE ) ) );
  2074. }
  2075. }
  2076. }
  2077. }
  2078. }
  2079. }
  2080. if ( IsWindow( updateWnd ) )
  2081. {
  2082. EnableWindowDlgItem( updateWnd, IDC_GET_UPDATE, TRUE );
  2083. SetDlgItemTextW( updateWnd, IDC_GET_UPDATE, WASABI_API_LNGSTRINGW( IDS_CHECK_FOR_UPDATES ) );
  2084. }
  2085. }
  2086. void OnError( DownloadToken token )
  2087. {
  2088. if ( IsWindow( updateWnd ) )
  2089. {
  2090. ShowWindowDlgItem( updateWnd, IDC_STATIC_UPDATE, TRUE );
  2091. SetDlgItemTextW( updateWnd, IDC_STATIC_UPDATE, WASABI_API_LNGSTRINGW( IDS_CHECK_UPDATE_FAIL ) );
  2092. EnableWindowDlgItem( updateWnd, IDC_GET_UPDATE, TRUE );
  2093. SetDlgItemTextW( updateWnd, IDC_GET_UPDATE, WASABI_API_LNGSTRINGW( IDS_CHECK_FOR_UPDATES ) );
  2094. }
  2095. }
  2096. RECVS_DISPATCH;
  2097. };
  2098. #define CBCLASS VersionCheckCallback
  2099. START_DISPATCH;
  2100. VCB( IFC_DOWNLOADMANAGERCALLBACK_ONINIT, OnInit )
  2101. VCB( IFC_DOWNLOADMANAGERCALLBACK_ONFINISH, OnFinish )
  2102. VCB( IFC_DOWNLOADMANAGERCALLBACK_ONERROR, OnError )
  2103. END_DISPATCH;
  2104. #undef CBCLASS
  2105. static VersionCheckCallback versionCheckCallback;
  2106. static void CheckVersion( HWND hDlg )
  2107. {
  2108. ShowWindowDlgItem( hDlg, IDC_STATIC_UPDATE, FALSE );
  2109. ShowWindowDlgItem( hDlg, IDC_UPDATELINK, FALSE );
  2110. if ( WAC_API_DOWNLOADMANAGER )
  2111. {
  2112. char url[ 128 ] = { 0 };
  2113. StringCchPrintf( url, ARRAYSIZE( url ), "http://yp.shoutcast.com/update?c=dsp_sc&v=%s&wa=%x", APP_Version, GetWinampVersion( module.hwndParent ) );
  2114. updateWnd = hDlg;
  2115. WAC_API_DOWNLOADMANAGER->DownloadEx( url, &versionCheckCallback, api_downloadManager::DOWNLOADEX_BUFFER );
  2116. }
  2117. else
  2118. {
  2119. wchar_t title[ 128 ] = { 0 }, message[ 512 ] = { 0 };
  2120. StringCchPrintfW( title, ARRAYSIZE( title ), LocalisedString( IDS_PLUGIN_NAME, NULL, 0 ), APP_VersionW );
  2121. StringCchPrintfW( message, ARRAYSIZE( message ), LocalisedString( IDS_UPDATE_CHECK_ERROR, NULL, 0 ) );
  2122. if ( MessageBoxW( module.hwndParent, message, title, MB_ICONWARNING | MB_YESNO ) == IDYES )
  2123. {
  2124. SendMessage( module.hwndParent, WM_WA_IPC, (WPARAM)DOWNLOAD_URL, IPC_OPEN_URL );
  2125. }
  2126. SetDlgItemTextW( hDlg, IDC_GET_UPDATE, WASABI_API_LNGSTRINGW( IDS_CHECK_FOR_UPDATES ) );
  2127. EnableWindowDlgItem( hDlg, IDC_GET_UPDATE, TRUE );
  2128. }
  2129. }
  2130. INT_PTR CALLBACK AboutFunc(HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam) {
  2131. if (uMsg == WM_COMMAND) {
  2132. switch(LOWORD(wParam))
  2133. {
  2134. case IDC_ABOUTLINK:
  2135. {
  2136. SendMessage(module.hwndParent, WM_WA_IPC, (WPARAM)"http://www.shoutcast.com/", IPC_OPEN_URL);
  2137. }
  2138. break;
  2139. case IDC_HELPLINK:
  2140. {
  2141. // look for a lcoal copy of the documentation otherwise then do as before and use the wiki verison
  2142. wchar_t path[MAX_PATH] = {0};
  2143. StringCchPrintfW(path, ARRAYSIZE(path), L"%s\\SHOUTcast Source DSP\\Source_DSP_Plug-in.html", GetPluginDirectoryW(module.hwndParent));
  2144. if(ShellExecuteW(module.hwndParent, L"open", path, NULL, NULL, SW_SHOWNORMAL) < (HINSTANCE)32)
  2145. {
  2146. SendMessage(module.hwndParent, WM_WA_IPC, (WPARAM)L"http://wiki.shoutcast.com/wiki/Source_DSP_Plug-in", IPC_OPEN_URL);
  2147. }
  2148. }
  2149. break;
  2150. case IDC_FORUMLINK:
  2151. {
  2152. SendMessage(module.hwndParent, WM_WA_IPC, (WPARAM)L"http://forums.shoutcast.com/forumdisplay.php?f=140", IPC_OPEN_URL);
  2153. }
  2154. break;
  2155. case IDC_UPDATELINK:
  2156. {
  2157. SendMessage(module.hwndParent, WM_WA_IPC, (WPARAM)DOWNLOAD_URL, IPC_OPEN_URL);
  2158. }
  2159. break;
  2160. case IDC_ABOUT_ICON:
  2161. {
  2162. if (HIWORD(wParam) == STN_DBLCLK) {
  2163. static bool toggle;
  2164. SendDlgItemMessage(hDlg, IDC_ABOUT_ICON, STM_SETIMAGE, IMAGE_ICON, (LPARAM)GetICYIcon(!toggle));
  2165. SendMessage(hMainDLG, WM_SETICON, ICON_SMALL, (LPARAM)GetICYIcon(!toggle));
  2166. toggle = !toggle;
  2167. }
  2168. }
  2169. break;
  2170. case IDC_GET_UPDATE:
  2171. {
  2172. EnableWindowDlgItem(hDlg, IDC_GET_UPDATE, FALSE);
  2173. SetDlgItemTextW(hDlg, IDC_GET_UPDATE, WASABI_API_LNGSTRINGW(IDS_CHECKING_FOR_UPDATES));
  2174. CheckVersion(hDlg);
  2175. }
  2176. break;
  2177. }
  2178. }
  2179. LRESULT ret = CallWindowProcW((WNDPROC)DialogFunc, hDlg, uMsg, wParam, lParam);
  2180. link_handledraw(hDlg, uMsg, wParam, lParam);
  2181. return ret;
  2182. }
  2183. void UpdateTitleControls(void) {
  2184. MY_T_OUTPUT *Out = &Output[Connection_CurSelPos];
  2185. if (Out->Config.doTitleUpdate) {
  2186. int length = (GetWindowTextLength(GetDlgItem(out_wnd[3].hWnd, IDC_TITLE)) > 0);
  2187. int sc2mode = (LOBYTE(Output[Connection_CurSelPos].Config.protocol) == 1);
  2188. EnableWindowDlgItem(out_wnd[3].hWnd, IDC_SENDNEXTTITLES, Out->AutoTitle && !sc2mode);
  2189. if (Out->AutoTitle) {
  2190. EnableWindowDlgItem(out_wnd[3].hWnd, IDC_SEND, FALSE);
  2191. EnableWindowDlgItem(out_wnd[3].hWnd, IDC_TITLE, FALSE);
  2192. EnableWindowDlgItem(out_wnd[3].hWnd, IDC_NEXT, FALSE);
  2193. } else {
  2194. EnableWindowDlgItem(out_wnd[3].hWnd, IDC_SEND, length);
  2195. EnableWindowDlgItem(out_wnd[3].hWnd, IDC_TITLE, TRUE);
  2196. EnableWindowDlgItem(out_wnd[3].hWnd, IDC_NEXT, !sc2mode && length);
  2197. }
  2198. } else {
  2199. EnableWindowDlgItem(out_wnd[3].hWnd, IDC_SEND, FALSE);
  2200. EnableWindowDlgItem(out_wnd[3].hWnd, IDC_TITLE, FALSE);
  2201. EnableWindowDlgItem(out_wnd[3].hWnd, IDC_NEXT, FALSE);
  2202. EnableWindowDlgItem(out_wnd[3].hWnd, IDC_SENDNEXTTITLES, FALSE);
  2203. }
  2204. }
  2205. void LockOptionControls(BOOL unlock) {
  2206. int protocol = LOBYTE(Output[Connection_CurSelPos].Config.protocol),
  2207. automatic = (HIBYTE(Output[Connection_CurSelPos].Config.protocol) == 1);
  2208. BOOL sc1 = (protocol == 1);
  2209. // First Connection panel
  2210. EnableWindowDlgItem(out_wnd[0].hWnd, IDC_ADDRESS, unlock);
  2211. EnableWindowDlgItem(out_wnd[0].hWnd, IDC_PORT, unlock);
  2212. // ensure the SC2 items are enabled only if SC1 mode is disabled
  2213. EnableWindowDlgItem(out_wnd[0].hWnd, IDC_STATIONID, (sc1 ? FALSE : unlock));
  2214. EnableWindowDlgItem(out_wnd[0].hWnd, IDC_USERID, unlock);
  2215. EnableWindowDlgItem(out_wnd[0].hWnd, IDC_PASSWORD, unlock);
  2216. EnableWindowDlgItem(out_wnd[0].hWnd, IDC_RECONNECT, unlock);
  2217. EnableWindowDlgItem(out_wnd[0].hWnd, IDC_TIMEOUT, unlock);
  2218. EnableWindowDlgItem(out_wnd[0].hWnd, IDC_PROTOCOL, unlock);
  2219. // controls the information shown on the connection panel
  2220. //ShowWindowDlgItem(out_wnd[0].hWnd, IDC_INFO_FRAME2, !sc1);
  2221. ShowWindowDlgItem(out_wnd[0].hWnd, IDC_INFO_TEXT2, (protocol == 2) && !automatic);
  2222. ShowWindowDlgItem(out_wnd[0].hWnd, IDC_INFO_TEXT3, (protocol == 1) && !automatic);
  2223. ShowWindowDlgItem(out_wnd[0].hWnd, IDC_INFO_TEXT4, automatic);
  2224. // artwork panel controls
  2225. ShowWindowDlgItem(out_wnd[4].hWnd, IDC_USE_ART, !sc1);
  2226. ShowWindowDlgItem(out_wnd[4].hWnd, IDC_USE_ART_PLAYING, !sc1);
  2227. ShowWindowDlgItem(out_wnd[4].hWnd, IDC_USE_ART_STREAM, !sc1);
  2228. ShowWindowDlgItem(out_wnd[4].hWnd, IDC_ART_EDIT, !sc1);
  2229. ShowWindowDlgItem(out_wnd[4].hWnd, IDC_ART_BROWSE, !sc1);
  2230. ShowWindowDlgItem(out_wnd[4].hWnd, IDC_ART_V1_NOTE, sc1);
  2231. ShowWindowDlgItem(out_wnd[4].hWnd, IDC_ARTWORK_V1_FRAME, sc1);
  2232. ShowWindowDlgItem(out_wnd[4].hWnd, IDC_ART_V2_NOTE, !sc1);
  2233. ShowWindowDlgItem(out_wnd[4].hWnd, IDC_ARTWORK_V2_FRAME, !sc1);
  2234. // Second Connection panel
  2235. EnableWindowDlgItem(out_wnd[1].hWnd, IDC_PUBLIC, unlock);
  2236. EnableWindowDlgItem(out_wnd[1].hWnd, IDC_DESCRIPTION, unlock);
  2237. EnableWindowDlgItem(out_wnd[1].hWnd, IDC_SERVERURL, unlock);
  2238. EnableWindowDlgItem(out_wnd[1].hWnd, IDC_GENRE, FALSE);
  2239. EnableWindowDlgItem(out_wnd[1].hWnd, IDC_GENRES, unlock);
  2240. // ensure the SC1 items are enabled only if SC1 mode is enabled
  2241. EnableWindowDlgItem(out_wnd[1].hWnd, IDC_AIM, (!sc1 ? FALSE : unlock));
  2242. EnableWindowDlgItem(out_wnd[1].hWnd, IDC_ICQ, (!sc1 ? FALSE : unlock));
  2243. EnableWindowDlgItem(out_wnd[1].hWnd, IDC_IRC, (!sc1 ? FALSE : unlock));
  2244. // Encoder tab
  2245. EnableWindowDlgItem(out_wnd[2].hWnd, IDC_ENCTYPE, unlock);
  2246. EnableWindowDlgItem(out_wnd[2].hWnd, IDC_ENCSETTINGS_BUTTON, unlock);
  2247. EnableWindowDlgItem(out_wnd[2].hWnd, IDC_ENCSETTINGS, unlock);
  2248. }
  2249. void WritePrivateProfileInt(LPCSTR lpKeyName, int value, LPCSTR lpAppName, LPCSTR lpFileName) {
  2250. char tmp[64] = {0};
  2251. StringCchPrintfA(tmp, ARRAYSIZE(tmp), "%u", value);
  2252. WritePrivateProfileString((!lpAppName ? APP_Name : lpAppName), lpKeyName, tmp, (!lpFileName ? IniName : lpFileName));
  2253. }
  2254. wchar_t* GetFileMetaData(wchar_t* file, wchar_t* metadata, wchar_t* buffer, int buffer_len) {
  2255. extendedFileInfoStructW efs;
  2256. efs.filename=file;
  2257. efs.metadata=metadata;
  2258. efs.ret=buffer;
  2259. efs.retlen=buffer_len;
  2260. SendMessage(module.hwndParent, WM_WA_IPC, (WPARAM)&efs, IPC_GET_EXTENDED_FILE_INFOW);
  2261. return buffer;
  2262. }
  2263. void UpdateNextTracks(wchar_t* next, int pos, std::vector<int> &nextListIdx, std::vector<std::wstring> &nextList) {
  2264. nextList.clear();
  2265. nextListIdx.clear();
  2266. int queued = (WASABI_API_QUEUEMGR ? WASABI_API_QUEUEMGR->GetNumberOfQueuedItems() : 0);
  2267. if (WASABI_API_QUEUEMGR && queued) {
  2268. for (int i = 0; i < queued && (lookAhead == -1 ? 1 : i < lookAhead); i++) {
  2269. int idx = WASABI_API_QUEUEMGR->GetQueuedItemFromIndex(i);
  2270. nextList.push_back((wchar_t*)SendMessage(module.hwndParent, WM_WA_IPC, idx, IPC_GETPLAYLISTTITLEW));
  2271. nextListIdx.push_back(idx);
  2272. }
  2273. } else {
  2274. if (next[0]) {
  2275. nextList.push_back(next);
  2276. nextListIdx.push_back(pos);
  2277. }
  2278. }
  2279. }
  2280. int GetNextTracks(int len, int pos, wchar_t* next) {
  2281. int nextpos = SendMessage(module.hwndParent, WM_WA_IPC, 0, IPC_GETNEXTLISTPOS);
  2282. // attempt to use the new look ahead api in 5.61+ otherwise use existing
  2283. // method or if the new api returns a failure just to cover all bases
  2284. if (doNextLookAhead && nextpos != -1 && len >= 1) {
  2285. wcscpy_s((wchar_t*)next, 1024, (wchar_t*)SendMessage(module.hwndParent, WM_WA_IPC, nextpos, IPC_GETPLAYLISTTITLEW));
  2286. } else {
  2287. // get the next title (as long as shuffle is off, etc)
  2288. // with it mapped back to the first track as appropriate
  2289. if (len >= 2 && !SendMessage(module.hwndParent, WM_WA_IPC, 0, IPC_GET_SHUFFLE)) {
  2290. pos = (pos >= len ? 0 : pos);
  2291. wcscpy_s((wchar_t*)next, 1024, (wchar_t*)SendMessage(module.hwndParent, WM_WA_IPC, pos, IPC_GETPLAYLISTTITLEW));
  2292. }
  2293. }
  2294. return pos;
  2295. }
  2296. void FillNextTracks(int index, bool xml) {
  2297. // on change then we refresh the file as applicable
  2298. std::vector<std::wstring> nextList;
  2299. std::vector<int> nextListIdx;
  2300. wchar_t next[1024] = {0};
  2301. int curpos = SendMessage(module.hwndParent, WM_WA_IPC, 0, IPC_GETLISTPOS);
  2302. int len = SendMessage(module.hwndParent, WM_WA_IPC, 0, IPC_GETLISTLENGTH);
  2303. int pos = curpos + 1;
  2304. pos = GetNextTracks(len, pos, next);
  2305. UpdateNextTracks(next, pos, nextListIdx, nextList);
  2306. WriteNextTracks(index, module.hwndParent, nextListIdx, nextList, xml);
  2307. }
  2308. static ARGB32 *loadImgFromFile(const wchar_t *file, int *len)
  2309. {
  2310. *len = 0;
  2311. HANDLE hf = CreateFileW(file, GENERIC_READ, FILE_SHARE_READ, 0, OPEN_EXISTING, 0, 0);
  2312. if (hf != INVALID_HANDLE_VALUE)
  2313. {
  2314. *len = GetFileSize(hf, 0);
  2315. if (WASABI_API_MEMMGR) {
  2316. ARGB32* im = (ARGB32 *)WASABI_API_MEMMGR->sysMalloc(*len);
  2317. if (im) {
  2318. DWORD bytes_read;
  2319. ReadFile(hf, im, *len, &bytes_read, 0);
  2320. CloseHandle(hf);
  2321. return im;
  2322. }
  2323. }
  2324. CloseHandle(hf);
  2325. }
  2326. return (ARGB32 *)-1;
  2327. }
  2328. static wchar_t bytes[32], kilo[32], mega[32], giga[32], tera[32];
  2329. wchar_t* sizeStr(unsigned int size) {
  2330. static wchar_t temp[256];
  2331. if (GetWinampVersion(module.hwndParent) >= 0x5064) {
  2332. // TODO swap over to the native Winamp version on newer clients
  2333. return WASABI_API_LNG->FormattedSizeString(temp, ARRAYSIZE(temp), size);
  2334. } else {
  2335. if (!bytes[0]) {
  2336. LocalisedString(IDS_B, bytes, ARRAYSIZE(bytes));
  2337. LocalisedString(IDS_KIB, kilo, ARRAYSIZE(kilo));
  2338. LocalisedString(IDS_MIB, mega, ARRAYSIZE(mega));
  2339. LocalisedString(IDS_GIB, giga, ARRAYSIZE(giga));
  2340. }
  2341. if(size < 1024) {
  2342. StringCchPrintfW(temp, ARRAYSIZE(temp), L"%u %s", size, bytes);
  2343. } else if(size < 1048576) {
  2344. StringCchPrintfW(temp, ARRAYSIZE(temp), L"%.02f %s", (size / 1024.0f), kilo);
  2345. } else if(size < 1073741824) {
  2346. StringCchPrintfW(temp, ARRAYSIZE(temp), L"%.02f %s", (size / 1048576.0f), mega);
  2347. } else if(size < 1099511627776){
  2348. StringCchPrintfW(temp, ARRAYSIZE(temp), L"%.02f %s", (size / 1073741824.0f), giga);
  2349. } else{
  2350. StringCchPrintfW(temp, ARRAYSIZE(temp), L"%.02f %s", (size / 1073741824.0f), tera);
  2351. }
  2352. }
  2353. return temp;
  2354. }
  2355. void UpdateArtworkMessage() {
  2356. MY_T_OUTPUT *Out = &Output[Connection_CurSelPos];
  2357. SHOUTCAST_OUTPUT *Enc = Out->Encoder != -1 ? &Encoder[Out->Encoder] : NULL;
  2358. wchar_t buf[1024], playing[256], stream[256];
  2359. T_OUTPUT_INFO *Info = Enc->GetOutputInfo(Out->Handle);
  2360. int streamSize = (Info ? Info->art_cached_length[0] : 0),
  2361. playingSize = (Info ? Info->art_cached_length[1] : 0);
  2362. StringCchPrintfW(stream, ARRAYSIZE(stream),
  2363. WASABI_API_LNGSTRINGW(!Out->useArt || !Out->useStreamArt ? IDS_DISABLED :
  2364. (streamSize == 0 ? IDS_EMPTY_ART : IDS_ENABLED_SIZE)),
  2365. sizeStr(streamSize));
  2366. StringCchPrintfW(playing, ARRAYSIZE(playing),
  2367. WASABI_API_LNGSTRINGW(!Out->useArt || !Out->usePlayingArt ? IDS_DISABLED :
  2368. (playingSize == 0 ? IDS_EMPTY_ART : IDS_ENABLED_SIZE)),
  2369. sizeStr(playingSize));
  2370. StringCchPrintfW(buf, ARRAYSIZE(buf), WASABI_API_LNGSTRINGW(IDS_V2_ARTWORK), stream, playing);
  2371. SetDlgItemTextW(out_wnd[4].hWnd, IDC_ART_V2_NOTE, buf);
  2372. }
  2373. void UpdatePlayingAlbumArt(int Connection, int Index, bool usePlayingArt) {
  2374. // do some quick checks as no need to send if not applicable to do so
  2375. if (!usePlayingArt && !playingImage) {
  2376. return;
  2377. }
  2378. // hard code the playing art to be sent in png format
  2379. Encoder[Index].UpdateAlbumArtCache((usePlayingArt ? playingImage : 0),
  2380. (usePlayingArt ? playingLength : 0),
  2381. playingType, Connection);
  2382. UpdateArtworkMessage();
  2383. }
  2384. bool UpdateStreamAlbumArt(int Connection, int Index, const wchar_t* stationArtPath, bool useStreamArt) {
  2385. int artType = 0x0;
  2386. bool update = false;
  2387. // if not enabled and loaded then unload and refresh
  2388. if (!useStreamArt && streamImage[Index] != (ARGB32 *)-1) {
  2389. FreeStreamAlbumArt(Index);
  2390. // bit of a fiddle to force a dummy update
  2391. artType = 0x4000;
  2392. update = true;
  2393. } else if (useStreamArt && streamImage[Index] != (ARGB32 *)-1) {
  2394. FreeStreamAlbumArt(Index);
  2395. }
  2396. // if enabled and not loaded then attempt to load
  2397. if (!update && streamImage[Index] == (ARGB32 *)-1) {
  2398. if (useStreamArt) {
  2399. streamImage[Index] = loadImgFromFile(stationArtPath, &streamLength[Index]);
  2400. wchar_t* ext = PathFindExtensionW(stationArtPath);
  2401. if (ext) {
  2402. if (*ext) ext++;
  2403. update = true;
  2404. if (!wcsnicmp(ext, L"jpeg", 4) || !wcsnicmp(ext, L"jpg", 3)) {
  2405. artType = 0x4000;
  2406. } else if (!wcsnicmp(ext, L"png", 3)) {
  2407. artType = 0x4001;
  2408. } else if (!wcsnicmp(ext, L"bmp", 3)) {
  2409. artType = 0x4002;
  2410. } else if (!wcsnicmp(ext, L"gif", 3)) {
  2411. artType = 0x4003;
  2412. } else {
  2413. update = false;
  2414. }
  2415. }
  2416. } else {
  2417. // if not enabled and not loaded then do nothing
  2418. UpdateArtworkMessage();
  2419. return false;
  2420. }
  2421. }
  2422. if (update) {
  2423. Encoder[Index].UpdateAlbumArtCache((!useStreamArt || streamImage[Index] == (ARGB32 *)-1 ? 0 : streamImage[Index]),
  2424. (!useStreamArt ? 0: streamLength[Index]), artType, Connection);
  2425. }
  2426. UpdateArtworkMessage();
  2427. return update;
  2428. }
  2429. void UpdateVUMeters()
  2430. {
  2431. int volume = 0;
  2432. int vu_l = VU.vu_l;
  2433. int vu_r = VU.vu_r;
  2434. VU.vu_l = 0;
  2435. VU.vu_r = 0;
  2436. VU.lastUpdate = VU.update;
  2437. VU.update = 0;
  2438. wchar_t tmp[256], temp[32], temp2[32];
  2439. if (vu_l != 0) {
  2440. volume = (int) (20 * log10((double) vu_l));
  2441. StringCchPrintfW(tmp, ARRAYSIZE(tmp), LocalisedString(IDS_X_DB, temp, 32), volume - 90);
  2442. } else {
  2443. volume = 0;
  2444. LocalisedString(IDS_INF_DB, tmp, 256);
  2445. }
  2446. if (volume - 90 > peak_vu_l) {
  2447. StringCchPrintfW(temp2, ARRAYSIZE(temp2), LocalisedString(IDS_X_DB_PEAK, temp, 32), (peak_vu_l = volume - 90));
  2448. SetDlgItemTextW(wnd[0].hWnd, IDC_VOLUMETEXT_LP, temp2);
  2449. SetDlgItemTextW(wnd[2].hWnd, IDC_VOLUMETEXT_LP, temp2);
  2450. }
  2451. SetDlgItemTextW(wnd[0].hWnd, IDC_VOLUMETEXT_L, tmp);
  2452. SendDlgItemMessage(wnd[0].hWnd, IDC_VOLUMEGRAPH_L, PBM_SETPOS, volume, 0);
  2453. SetDlgItemTextW(wnd[2].hWnd, IDC_VOLUMETEXT_L, tmp);
  2454. SendDlgItemMessage(wnd[2].hWnd, IDC_VOLUMEGRAPH_L, PBM_SETPOS, volume, 0);
  2455. if (vu_r != 0) {
  2456. volume = (int) (20 * log10((double) vu_r));
  2457. StringCchPrintfW(tmp, ARRAYSIZE(tmp), LocalisedString(IDS_X_DB, temp, 32), volume - 90);
  2458. } else {
  2459. volume = 0;
  2460. LocalisedString(IDS_INF_DB, tmp, 256);
  2461. }
  2462. if (volume - 90 > peak_vu_r) {
  2463. StringCchPrintfW(temp2, ARRAYSIZE(temp2), LocalisedString(IDS_X_DB_PEAK, temp, 32), (peak_vu_r = volume - 90));
  2464. SetDlgItemTextW(wnd[0].hWnd, IDC_VOLUMETEXT_RP, temp2);
  2465. SetDlgItemTextW(wnd[2].hWnd, IDC_VOLUMETEXT_RP, temp2);
  2466. }
  2467. SetDlgItemTextW(wnd[0].hWnd, IDC_VOLUMETEXT_R, tmp);
  2468. SendDlgItemMessage(wnd[0].hWnd, IDC_VOLUMEGRAPH_R, PBM_SETPOS, volume, 0);
  2469. SetDlgItemTextW(wnd[2].hWnd, IDC_VOLUMETEXT_R, tmp);
  2470. SendDlgItemMessage(wnd[2].hWnd, IDC_VOLUMEGRAPH_R, PBM_SETPOS, volume, 0);
  2471. }
  2472. void UpdateSummaryDetails(int item) {
  2473. if (item == -1) {
  2474. return;
  2475. }
  2476. wchar_t message[2048], temp[128], temp2[128], temp3[128],
  2477. temp4[128] = {0}, temp5[128], temp6[128], temp7[128];
  2478. char temp8[128];
  2479. MY_T_OUTPUT *Out = &Output[item];
  2480. C_ENCODER *Enc = Encoder[Out->Encoder].GetEncoder();
  2481. if (Enc) {
  2482. StringCchPrintfW(temp4, ARRAYSIZE(temp4), LocalisedString(IDS_SUMMARY_KBPS, NULL, 0), ((T_EncoderIOVals*) Enc->GetExtInfo())->output_bitRate);
  2483. }
  2484. StringCchPrintfW(message, ARRAYSIZE(message), LocalisedString(IDS_SUMMARY, NULL, 0),
  2485. // TODO show automatic mode ?
  2486. (LOBYTE(Out->Config.protocol) != 1 ? 2 : 1),
  2487. LocalisedString((Out->Config.Public ? IDS_PUBLIC : IDS_PRIVATE), temp, 128),
  2488. (Out->Config.Address[0] ? Out->Config.Address : LocalisedStringA(IDS_NOT_SET_SUMMARY, temp8, 128)),
  2489. Out->Config.Port,
  2490. LocalisedString((Out->Config.doTitleUpdate ? (Out->AutoTitle ? IDS_FOLLOW_WA : IDS_MANUAL) : IDS_DISABLED), temp2, 128),
  2491. (Enc_LastType[item] != 0 ? (!strcmp(Encoder[Out->Encoder].GetEncoder()->GetContentType(),"audio/mpeg")?L"MP3":L"AAC+") : LocalisedString(IDS_NOT_SET, temp3, 128)),
  2492. temp4,
  2493. LocalisedString((Out->Logging ? IDS_YES : IDS_NO), temp5, 128),
  2494. LocalisedString((Out->AutoConnect ? IDS_YES : IDS_NO), temp6, 128),
  2495. LocalisedString((Out->saveEncoded ? IDS_YES : IDS_NO), temp7, 128));
  2496. SetDlgItemTextW(wnd[0].hWnd, IDC_SUMMARY, message);
  2497. // see if we're looking at a incomplete setup and flag up the output tab as applicable
  2498. if (IsWindow(tabWnd)) {
  2499. RECT r = {0};
  2500. TabCtrl_GetItemRect(tabWnd, 1, &r);
  2501. if ((lastMode[item] >= 3 && lastMode[item] <= 6)) {
  2502. SetTabErrorText(tabWnd, 1, 0, &r);
  2503. } else {
  2504. InvalidateRect(tabWnd, &r, 0);
  2505. }
  2506. }
  2507. }
  2508. void ProcessPlayingStatusUpdate(void) {
  2509. if (isplaying == 1 && SendMessage(module.hwndParent, WM_WA_IPC, 0, IPC_GETOUTPUTTIME)) {
  2510. if (was_paused) {
  2511. was_paused = 0;
  2512. play_diff = GetTickCount();
  2513. }
  2514. } else if (isplaying == 3) {
  2515. // pause
  2516. was_paused = 1;
  2517. } else if (isplaying == 0 && was_playing == 1) {
  2518. // stop
  2519. was_playing = was_paused = 0;
  2520. } else if (isplaying == 0 && was_playing == 0) {
  2521. // non-playing track advance
  2522. PostMessage(hMainDLG, WM_USER, 0, nowPlayingID);
  2523. }
  2524. }
  2525. // check against a list of known "illegal" names as well as not allowing
  2526. // the creation of a station with the name the same as a genre string
  2527. bool stationNameAllowed(char* name){
  2528. if(name && *name)
  2529. {
  2530. int checked = 0;
  2531. for (int i = 0; i < ARRAYSIZE(genres); i++) {
  2532. checked += !lstrcmpi(name, genres[i].name);
  2533. }
  2534. // check for punctuation only titles with double-processing
  2535. // to strip out alphanum+space and space in second and then
  2536. // we compare a difference in lengths where different is ok
  2537. if (lstrlen(name) > 0) {
  2538. char* stripped = (char*)malloc(lstrlen(name)+1);
  2539. char* stripped2 = (char*)malloc(lstrlen(name)+1);
  2540. stripped[0] = 0;
  2541. for(int i = 0, j = 0; i < lstrlen(name); i++) {
  2542. if(!isalnum(name[i]) && name[i] != ' ') {
  2543. stripped[j] = name[i];
  2544. stripped[++j] = 0;
  2545. }
  2546. }
  2547. for(int i = 0, j = 0; i < lstrlen(name); i++) {
  2548. if(name[i] != ' ') {
  2549. stripped2[j] = name[i];
  2550. stripped2[++j] = 0;
  2551. }
  2552. }
  2553. checked += !(lstrlen(stripped2) > lstrlen(stripped));
  2554. free(stripped);
  2555. free(stripped2);
  2556. }
  2557. char* invalidNames[] = {"127.0.0.1", "admin", "auto dj", "auto jedi", "auto pj",
  2558. "auto-dj", "autodj", "autopj", "demo", "dj", "internet radio",
  2559. "live", "local server", "localhost", "localserver", "music",
  2560. "my radio", "my server", "my station name", "my test server",
  2561. "n/a", "pj", "playlist", "radio", "radio station", "test",
  2562. "test server", "unnamed server", "virtual dj", "virtualdj",
  2563. "web rdio", "web radio", "song", "teste", "default stream",
  2564. "radio stream", "whmsonic autodj", "autopilot",
  2565. "this is my server name"};
  2566. for(int i = 0; i < ARRAYSIZE(invalidNames); i++)
  2567. {
  2568. checked += !lstrcmpi(name, invalidNames[i]);
  2569. }
  2570. return (!checked);
  2571. }
  2572. return false;
  2573. }
  2574. HBITMAP WAResizeImage(HBITMAP hbmp, INT cx, INT cy) {
  2575. BITMAP bi = {0};
  2576. if (!hbmp || !GetObjectW(hbmp, sizeof(BITMAP), &bi)) return hbmp;
  2577. if (bi.bmWidth != cx || bi.bmHeight != cy) {
  2578. HDC hdc, hdcDst, hdcSrc;
  2579. HBITMAP hbmpOld1, hbmpOld2;
  2580. int ix = cy*(bi.bmWidth*1000/bi.bmHeight)/1000, iy;
  2581. if (ix > cx) {
  2582. iy = cx*(bi.bmHeight*1000/bi.bmWidth)/1000;
  2583. ix = cx;
  2584. }
  2585. else iy = cy;
  2586. hdc = GetDC(NULL);
  2587. hdcSrc = CreateCompatibleDC(hdc);
  2588. hdcDst = CreateCompatibleDC(hdc);
  2589. hbmpOld1 = (HBITMAP)SelectObject(hdcSrc, hbmp);
  2590. hbmp = CreateCompatibleBitmap(hdc, cx, cy);
  2591. hbmpOld2 = (HBITMAP)SelectObject(hdcDst, hbmp);
  2592. if (ix != cx || iy != cy) {
  2593. RECT r;
  2594. SetRect(&r, 0, 0, cx, cy);
  2595. FillRect(hdcDst, &r, GetSysColorBrush(COLOR_BTNFACE));
  2596. }
  2597. SetStretchBltMode(hdcDst, HALFTONE);
  2598. StretchBlt(hdcDst, (cx - ix)/2, (cy - iy)/2, ix, iy, hdcSrc, 0, 0, bi.bmWidth, bi.bmHeight, SRCCOPY);
  2599. SelectObject(hdcDst, hbmpOld2);
  2600. hbmpOld2 = (HBITMAP)SelectObject(hdcSrc, hbmpOld1);
  2601. if (hbmpOld2) DeleteObject(hbmpOld2);
  2602. DeleteDC(hdcSrc);
  2603. DeleteDC(hdcDst);
  2604. ReleaseDC(NULL, hdc);
  2605. }
  2606. return hbmp;
  2607. }
  2608. HBITMAP getBitmap(ARGB32 * data, int w, int h)
  2609. {
  2610. BITMAPINFO info={0};
  2611. info.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
  2612. info.bmiHeader.biWidth = w;
  2613. info.bmiHeader.biHeight = -h;
  2614. info.bmiHeader.biPlanes = 1;
  2615. info.bmiHeader.biBitCount = 32;
  2616. info.bmiHeader.biCompression = BI_RGB;
  2617. HDC dc = GetDC(NULL);
  2618. HBITMAP bm = CreateCompatibleBitmap(dc, w, h);
  2619. SetDIBits(dc, bm, 0, h, data, &info, DIB_RGB_COLORS);
  2620. ReleaseDC(NULL, dc);
  2621. return WAResizeImage(bm, 155, 88);
  2622. }
  2623. ARGB32 * decompressImage(const void *data, int datalen, int * dataW, int * dataH) {
  2624. ARGB32* ret=NULL;
  2625. FOURCC imgload = svc_imageLoader::getServiceType();
  2626. int n = WASABI_API_SVC->service_getNumServices(imgload);
  2627. for (int i = 0; i < n; i++) {
  2628. waServiceFactory *sf = WASABI_API_SVC->service_enumService(imgload,i);
  2629. if (sf) {
  2630. svc_imageLoader * l = (svc_imageLoader*)sf->getInterface();
  2631. if (l) {
  2632. if (l->testData(data,datalen)) {
  2633. ret = l->loadImage(data,datalen,dataW,dataH);
  2634. sf->releaseInterface(l);
  2635. break;
  2636. }
  2637. sf->releaseInterface(l);
  2638. }
  2639. }
  2640. }
  2641. return ret;
  2642. }
  2643. INT_PTR CALLBACK DialogFunc(HWND hDlg, UINT uMsg, WPARAM wParam, LPARAM lParam) {
  2644. if (SYSTRAY_BASE_MSG + SYSTRAY_MAXIMIZE_MSG == uMsg) {
  2645. int which = LOWORD(wParam) - SYSTRAY_BASE_ICON;
  2646. switch (LOWORD(lParam)) {
  2647. case WM_LBUTTONDOWN:
  2648. {
  2649. switch (which) {
  2650. case 1:
  2651. {
  2652. RemoveSystrayIcon(hDlg, SYSTRAY_ICY_ICON);
  2653. ShowWindow(hDlg, SW_SHOW);
  2654. SendMessage(hDlg, WM_SYSCOMMAND, SC_RESTORE, 0);
  2655. }
  2656. break;
  2657. }
  2658. }
  2659. break;
  2660. }
  2661. }
  2662. switch (uMsg) {
  2663. #ifdef FOLLOW_MIXER
  2664. case MM_MIXM_CONTROL_CHANGE:
  2665. {
  2666. HMIXER mix = (HMIXER)wParam;
  2667. DWORD dwControlID = (DWORD)lParam;
  2668. //if (dwControlID == 3)
  2669. {
  2670. MIXERLINE ml = {sizeof (ml), 0};
  2671. ml.dwComponentType = MIXERLINE_COMPONENTTYPE_SRC_LINE;
  2672. ml.dwLineID = dwControlID;
  2673. if (mixerGetLineInfo((HMIXEROBJ) mix, &ml, MIXER_GETLINEINFOF_COMPONENTTYPE|MIXER_OBJECTF_MIXER) == MMSYSERR_NOERROR) {
  2674. MIXERLINECONTROLS mlc = {sizeof (mlc), dwControlID,};
  2675. MIXERCONTROL mc = {sizeof (mc),};
  2676. //mlc.cControls = 1;
  2677. mlc.cbmxctrl = sizeof (mc);
  2678. mlc.pamxctrl = &mc;
  2679. mlc.dwControlType = MIXERCONTROL_CONTROLTYPE_VOLUME;
  2680. //mlc.dwControlID = dwControlID;
  2681. mlc.dwLineID = dwControlID;//ml.dwLineID;
  2682. char a[128];
  2683. sprintf(a,"MM_MIXM_CONTROL_CHANGE: %d\n",dwControlID);
  2684. OutputDebugString(a);
  2685. if (mixerGetLineControls((HMIXEROBJ) mix, &mlc, MIXER_GETLINECONTROLSF_ONEBYTYPE|MIXER_OBJECTF_MIXER) == MMSYSERR_NOERROR) {
  2686. //MIXERCONTROLDETAILS mcd = {sizeof (mcd), 0,};
  2687. char a[128];
  2688. sprintf(a,"MM_MIXM_CONTROL_CHANGE 2: %d\n",dwControlID);
  2689. OutputDebugString(a);
  2690. /*MIXERCONTROLDETAILS_UNSIGNED v[2];
  2691. mcd.cbDetails = sizeof (MIXERCONTROLDETAILS_UNSIGNED);
  2692. mcd.paDetails = v;
  2693. /*v[0].dwValue = mc.Bounds.dwMinimum + (va * (mc.Bounds.dwMaximum - mc.Bounds.dwMinimum)) / 100;
  2694. v[1].dwValue = mc.Bounds.dwMinimum + (va * (mc.Bounds.dwMaximum - mc.Bounds.dwMinimum)) / 100;
  2695. MMRESULT result = mixerSetControlDetails((HMIXEROBJ) hmix, &mcd, MIXER_OBJECTF_MIXER);*/
  2696. }
  2697. }
  2698. }
  2699. }
  2700. break;
  2701. #endif
  2702. case WM_LBUTTONUP:
  2703. GetWindowRect(hDlg, &mainrect);
  2704. break;
  2705. case WM_INITDIALOG:
  2706. {
  2707. switch (lParam) {
  2708. case IDD_DIALOG:
  2709. {
  2710. int i;
  2711. wchar_t temp[128] = {0};
  2712. hMainDLG = hDlg;
  2713. for (i = 0; i < NUM_ENCODERS; i++) Enc_mutex[i] = NULL;
  2714. INITCOMMONCONTROLSEX ICCE;
  2715. ICCE.dwSize = sizeof (ICCE);
  2716. ICCE.dwICC = ICC_WIN95_CLASSES;
  2717. InitCommonControlsEx(&ICCE);
  2718. GetSCIniFile(module.hwndParent);
  2719. VU.update = VU.lastUpdate = 0;
  2720. memset(&VU, 0, sizeof (VU));
  2721. memset(&Output, 0, sizeof (Output));
  2722. // as only 5.61+ supports the IPC_GETNEXTLISTPOS api we check and cache version now
  2723. doNextLookAhead = (GetWinampVersion(module.hwndParent) >= 0x5061);
  2724. /* Load config */
  2725. LoadConfig();
  2726. /* Load Encoders */
  2727. LoadEncoders();
  2728. /* Start logging and encoded output saving */
  2729. for (i = 0; i < NUM_OUTPUTS; i++) {
  2730. if (Output[i].Logging) {
  2731. StartLogging(i, Output[i].LogCOS);
  2732. }
  2733. if (Output[i].nextTrackLog) {
  2734. StartNextTracks(i, Output[i].nextTrackPath);
  2735. }
  2736. if (Output[i].saveEncoded) {
  2737. StartSaveEncoded(i, Output[i].saveEncodedPath);
  2738. }
  2739. }
  2740. // ensure we've cached the title information, etc as needed before starting
  2741. isplaying = SendMessage(module.hwndParent, WM_WA_IPC, 0, IPC_ISPLAYING);
  2742. if (isplaying) ProcessPlayingStatusUpdate();
  2743. PostMessage(hDlg, WM_USER, 0, nowPlayingID);
  2744. /* Setup main tabs */
  2745. num_tabwnds = 0;
  2746. SendDlgItemMessage(hDlg, IDC_TAB, TCM_DELETEALLITEMS, 0, 0);
  2747. AddTab(IDD_MAIN, LocalisedString(IDS_TAB_MAIN, temp, 128), hDlg, DialogFunc, IDC_TAB, IDC_RECT, 100);
  2748. AddTab(IDD_CONNECTION, LocalisedString(IDS_TAB_OUTPUT, temp, 128), hDlg, ConnectionFunc, IDC_TAB, IDC_RECT, 100);
  2749. AddTab(IDD_INPUT, LocalisedString(IDS_TAB_INPUT, temp, 128), hDlg, DialogFunc, IDC_TAB, IDC_RECT, 100);
  2750. AddTab(IDD_ABOUT, LocalisedString(IDS_TAB_ABOUT, temp, 128), hDlg, AboutFunc, IDC_TAB, IDC_RECT, 100);
  2751. SetTab(curtab, hDlg, IDC_TAB);
  2752. /* threads and timer */
  2753. hthread = CreateThread(NULL, 0, ThreadInput, hDlg, CREATE_SUSPENDED, &threadid);
  2754. SetThreadPriority(hthread, THREAD_PRIORITY_HIGHEST);
  2755. hthreadout = CreateThread(NULL, 0, ThreadOutput, hDlg, CREATE_SUSPENDED, &threadoutid);
  2756. SetThreadPriority(hthreadout, THREAD_PRIORITY_HIGHEST);
  2757. Soundcard.Close();
  2758. Soundcard.Create((InputDevice == 0 ? InputConfig.srate : LineInputAttribs[Input_CurSelPos].srate), (InputDevice == 0 ? InputConfig.nch : LineInputAttribs[Input_CurSelPos].nch));
  2759. SetTimer(hDlg, 666, 300000, NULL); // start up INI save timer
  2760. FadeStartTime = 0;
  2761. MicFadeStartTime = 0;
  2762. FadeOut = 0;
  2763. ini_modified = 1;
  2764. ReleaseMutex(cf_mutex);
  2765. SendDlgItemMessage(wnd[1].hWnd, IDC_AUTOCONNECT, BM_SETCHECK,Output[Connection_CurSelPos].AutoConnect ? BST_CHECKED : BST_UNCHECKED, 0);
  2766. // deal with the PTT restore mode along with setting up the 'down arrow' button
  2767. SendDlgItemMessage(in_wnd[1].hWnd, IDC_LOCK, BM_SETCHECK, Restore_PTT ? BST_CHECKED : BST_UNCHECKED, 0);
  2768. PostMessage(in_wnd[1].hWnd, WM_COMMAND, MAKEWPARAM(IDC_LOCK, BN_CLICKED), (LPARAM)GetDlgItem(in_wnd[1].hWnd, IDC_LOCK));
  2769. SendDlgItemMessage(in_wnd[1].hWnd, IDC_LOCK_MODE, BM_SETIMAGE, IMAGE_ICON,
  2770. (LPARAM)LoadImage(module.hDllInstance, MAKEINTRESOURCE(IDI_DOWNARROW),
  2771. IMAGE_ICON, 0, 0, LR_SHARED | LR_LOADTRANSPARENT | LR_CREATEDIBSECTION));
  2772. SendDlgItemMessage(in_wnd[1].hWnd, IDC_REFRESH_DEVICES, BM_SETIMAGE, IMAGE_ICON,
  2773. (LPARAM)LoadImage(module.hDllInstance, MAKEINTRESOURCE(IDI_REFRESH),
  2774. IMAGE_ICON, 0, 0, LR_SHARED | LR_LOADTRANSPARENT | LR_CREATEDIBSECTION));
  2775. /* setup information parts to be in bold */
  2776. SetBoldDialogItemFont(GetDlgItem(wnd[0].hWnd, IDC_SUMMARY));
  2777. SetBoldDialogItemFont(GetDlgItem(out_wnd[1].hWnd, IDC_INFO_TEXT));
  2778. SetBoldDialogItemFont(GetDlgItem(out_wnd[0].hWnd, IDC_INFO_TEXT2));
  2779. SetBoldDialogItemFont(GetDlgItem(out_wnd[0].hWnd, IDC_INFO_TEXT3));
  2780. SetBoldDialogItemFont(GetDlgItem(out_wnd[0].hWnd, IDC_INFO_TEXT4));
  2781. SetBoldDialogItemFont(GetDlgItem(wnd[1].hWnd, IDC_CONNECT));
  2782. SetBoldDialogItemFont(GetDlgItem(out_wnd[4].hWnd, IDC_ART_V1_NOTE));
  2783. SetBoldDialogItemFont(GetDlgItem(out_wnd[4].hWnd, IDC_ART_V2_NOTE));
  2784. /* subclass the listview on the summary page for specific handling */
  2785. HWND listView = GetDlgItem(wnd[0].hWnd, IDC_OUTPUTSTATUS);
  2786. ListView_SetItemState(listView, 0, LVIS_SELECTED, LVIS_SELECTED);
  2787. prevListViewProc = (WNDPROC) SetWindowLongPtrW(listView, GWLP_WNDPROC, (LONG_PTR) listViewProc);
  2788. prevHeaderProc = (WNDPROC) SetWindowLongPtrW(ListView_GetHeader(listView), GWLP_WNDPROC, (LONG_PTR) headerProc);
  2789. /* subclass the tab control on the main dialog for error notifications */
  2790. tabWnd = GetDlgItem(hMainDLG, IDC_TAB);
  2791. prevTabWndProc = (WNDPROC) SetWindowLongPtrW(tabWnd, GWLP_WNDPROC, (LONG_PTR) tabWndProc);
  2792. /* subclass the tab control on the connection page for error notifications */
  2793. outTabWnd = GetDlgItem(wnd[1].hWnd, IDC_CONTAB);
  2794. prevOutTabWndProc = (WNDPROC) SetWindowLongPtrW(outTabWnd, GWLP_WNDPROC, (LONG_PTR) outTabWndProc);
  2795. /* only once everything else has been done then we start the threads */
  2796. ResumeThread(hthread);
  2797. ResumeThread(hthreadout);
  2798. break;
  2799. }
  2800. case IDD_MAIN:
  2801. {
  2802. HWND listView = GetDlgItem(hDlg, IDC_OUTPUTSTATUS);
  2803. ListView_DeleteAllItems(listView);
  2804. ListView_SetExtendedListViewStyle(listView, LVS_EX_FULLROWSELECT|LVS_EX_DOUBLEBUFFER|LVS_EX_LABELTIP);
  2805. AddColumn(L"", listView);
  2806. AddColumn(LocalisedString(IDS_COL_OUTPUT_NAME, NULL, 0), listView);
  2807. AddColumn(LocalisedString(IDS_COL_STATUS, NULL, 0), listView);
  2808. for (int i = 0; i < NUM_OUTPUTS; i++) {
  2809. AddColItem(L"", 0, hDlg, IDC_OUTPUTSTATUS);
  2810. AddColItem(Output[i].Config.DisplayName, 1, hDlg, IDC_OUTPUTSTATUS);
  2811. AddColItem(L"", 2, hDlg, IDC_OUTPUTSTATUS);
  2812. }
  2813. // fill the header of the output list with the column headers
  2814. ListView_SetColumnWidth(listView, 0, 24);//LVSCW_AUTOSIZE_USEHEADER);
  2815. ListView_SetColumnWidth(listView, 1, LVSCW_AUTOSIZE_USEHEADER);
  2816. int width = ListView_GetColumnWidth(listView, 0) + ListView_GetColumnWidth(listView, 1);
  2817. RECT listViewRect;
  2818. GetClientRect(listView, &listViewRect);
  2819. ListView_SetColumnWidth(listView, 2, (listViewRect.right - listViewRect.left) - width);
  2820. // add in status / action buttons for the first column...
  2821. for (int i = 0; i < NUM_OUTPUTS; i++) {
  2822. POINT pt;
  2823. ListView_GetItemPosition(listView, i, &pt);
  2824. ListView_GetItemRect(listView, i, &listViewRect, LVIR_BOUNDS);
  2825. buttonWnd[i] = CreateWindowW(L"button", L"", WS_VISIBLE | WS_CHILD | WS_CLIPSIBLINGS | WS_DISABLED | BS_ICON,
  2826. 1, pt.y, ListView_GetColumnWidth(listView, 0) - 3,
  2827. (listViewRect.bottom - listViewRect.top),
  2828. listView, (HMENU)(IDC_STREAM_1+i), 0, 0);
  2829. SendMessage(buttonWnd[i], BM_SETIMAGE, IMAGE_ICON,
  2830. (LPARAM)LoadImage(module.hDllInstance, MAKEINTRESOURCE(IDI_PLAY),
  2831. IMAGE_ICON, 0, 0, LR_SHARED | LR_LOADTRANSPARENT | LR_CREATEDIBSECTION));
  2832. }
  2833. CheckRadioButton(hDlg, IDC_INPUT_WINAMP, IDC_INPUT_SOUNDCARD, (IDC_INPUT_WINAMP + InputDevice));
  2834. SendDlgItemMessage(hDlg, IDC_VOLUMEGRAPH_L, PBM_SETRANGE, 0, MAKELONG(0, 90));
  2835. SendDlgItemMessage(hDlg, IDC_VOLUMEGRAPH_R, PBM_SETRANGE, 0, MAKELONG(0, 90));
  2836. for (int ii = 0; ii < NUM_OUTPUTS; ii++) {
  2837. int encnum = ii;
  2838. MY_T_OUTPUT *Out = &Output[ii];
  2839. // removed encoder selection
  2840. if (Out->Encoder != -1) {
  2841. if (Out->Handle != -1) {
  2842. if (WaitForSingleObject(Enc_mutex[Out->Encoder], INFINITE) == WAIT_OBJECT_0) {
  2843. Encoder[Out->Encoder].RemoveOutput(Out->Handle);
  2844. ReleaseMutex(Enc_mutex[Out->Encoder]);
  2845. }
  2846. }
  2847. }
  2848. Out->Encoder = encnum;
  2849. if (Out->Encoder != -1) {
  2850. if (WaitForSingleObject(Enc_mutex[Out->Encoder], INFINITE) == WAIT_OBJECT_0) {
  2851. Out->Handle = Encoder[Out->Encoder].AddOutput(Out->Encoder, &Out->Config, TitleCallback);
  2852. ReleaseMutex(Enc_mutex[Out->Encoder]);
  2853. }
  2854. ini_modified = 1;
  2855. }
  2856. // TODO
  2857. //SendMessage(hDlg, WM_COMMAND, MAKEWPARAM(IDC_NOTITLES, BN_CLICKED), (LPARAM) GetDlgItem(hDlg, IDC_NOTITLES));
  2858. }
  2859. break;
  2860. }
  2861. case IDD_INPUT:
  2862. {
  2863. SendDlgItemMessage(hDlg, IDC_INPUTDEVICE, CB_RESETCONTENT, 0, 0);
  2864. AddInTab(IDD_PANEL_WINAMP, LocalisedString(IDS_INPUT_WINAMP, NULL, 0), hDlg);
  2865. AddInTab(IDD_PANEL_LINEIN, LocalisedString(IDS_INPUT_SOUNDCARD, NULL, 0), hDlg);
  2866. SetInTab(InputDevice, hDlg, IDC_INPUTDEVICE);
  2867. EnableWindowDlgItem(hDlg, IDC_INPUTDEVICE, 1);
  2868. EnableWindowDlgItem(hDlg, IDC_INPUTDEVICESTATIC, 1);
  2869. SendDlgItemMessage(hDlg, IDC_VOLUMEGRAPH_L, PBM_SETRANGE, 0, MAKELONG(0, 90));
  2870. SendDlgItemMessage(hDlg, IDC_VOLUMEGRAPH_R, PBM_SETRANGE, 0, MAKELONG(0, 90));
  2871. break;
  2872. }
  2873. case IDD_ABOUT:
  2874. {
  2875. // this will make sure that we've got the icon shown even when using a localised version
  2876. // as well as setting the dialog icon to the icy icon irrespective of the dialog class's
  2877. SendDlgItemMessage(hDlg, IDC_ABOUT_ICON, STM_SETIMAGE, IMAGE_ICON, (LPARAM)GetICYIcon());
  2878. SendMessage(hMainDLG, WM_SETICON, ICON_SMALL, (LPARAM)GetICYIcon());
  2879. wchar_t about[1024], tmp[256];
  2880. StringCchPrintfW(about, ARRAYSIZE(about), LocalisedString(IDS_ABOUT_MESSAGE, NULL, 0),
  2881. LocalisedString(IDS_MODULE_NAME, tmp, 256),
  2882. APP_Version, APP_Build, __DATE__);
  2883. SetDlgItemTextW(hDlg, IDC_PROGRAMNAME, about);
  2884. link_startsubclass(hDlg, IDC_ABOUTLINK);
  2885. link_startsubclass(hDlg, IDC_HELPLINK);
  2886. link_startsubclass(hDlg, IDC_FORUMLINK);
  2887. link_startsubclass(hDlg, IDC_UPDATELINK);
  2888. ShowUpdateMessage(hDlg);
  2889. break;
  2890. }
  2891. case IDD_PANEL_WINAMP:
  2892. {
  2893. wchar_t buf[128] = {0};
  2894. inWinWa = hDlg;
  2895. HWND metalist = GetDlgItem(hDlg, IDC_METALIST);
  2896. ListView_SetExtendedListViewStyle(metalist, LVS_EX_FULLROWSELECT|LVS_EX_DOUBLEBUFFER|LVS_EX_LABELTIP);
  2897. AddColumn(L"", metalist);
  2898. AddColumn(L"", metalist);
  2899. AddColItem(LocalisedString(IDS_FILEPATH, buf, ARRAYSIZE(buf)), 0, hDlg, IDC_METALIST);
  2900. AddColItem(LocalisedString(IDS_TITLE, buf, ARRAYSIZE(buf)), 0, hDlg, IDC_METALIST);
  2901. AddColItem(LocalisedString(IDS_ARTIST, buf, ARRAYSIZE(buf)), 0, hDlg, IDC_METALIST);
  2902. AddColItem(LocalisedString(IDS_ALBUM, buf, ARRAYSIZE(buf)), 0, hDlg, IDC_METALIST);
  2903. AddColItem(LocalisedString(IDS_GENRE, buf, ARRAYSIZE(buf)), 0, hDlg, IDC_METALIST);
  2904. AddColItem(LocalisedString(IDS_YEAR, buf, ARRAYSIZE(buf)), 0, hDlg, IDC_METALIST);
  2905. AddColItem(LocalisedString(IDS_COMMENT, buf, ARRAYSIZE(buf)), 0, hDlg, IDC_METALIST);
  2906. ListView_SetColumnWidth(metalist, 0, LVSCW_AUTOSIZE);
  2907. RECT metalistRect;
  2908. GetClientRect(metalist, &metalistRect);
  2909. ListView_SetColumnWidth(metalist, 1, (metalistRect.right - metalistRect.left) - ListView_GetColumnWidth(metalist, 0));
  2910. break;
  2911. }
  2912. case IDD_PANEL_LINEIN:
  2913. {
  2914. inWin = NULL;
  2915. prevButtonProc = (WNDPROC) SetWindowLongPtrW(GetDlgItem(hDlg, IDC_PTT), GWLP_WNDPROC, (LONG_PTR) buttonProc);
  2916. SendDlgItemMessage(hDlg, IDC_MUSSLIDER, TBM_SETRANGE, TRUE, MAKELONG(0, 10));
  2917. SendDlgItemMessage(hDlg, IDC_MUS2SLIDER, TBM_SETRANGE, TRUE, MAKELONG(0, 10));
  2918. SendDlgItemMessage(hDlg, IDC_MICSLIDER, TBM_SETRANGE, TRUE, MAKELONG(0, 10));
  2919. SendDlgItemMessage(hDlg, IDC_FADESLIDER, TBM_SETRANGE, TRUE, MAKELONG(0, 25));
  2920. SendDlgItemMessage(hDlg, IDC_MICFADESLIDER, TBM_SETRANGE, TRUE, MAKELONG(0, 25));
  2921. SendDlgItemMessage(hDlg, IDC_MUSSLIDER, TBM_SETPOS, TRUE, MusVol);
  2922. SendDlgItemMessage(hDlg, IDC_MUS2SLIDER, TBM_SETPOS, TRUE, Mus2Vol);
  2923. SendDlgItemMessage(hDlg, IDC_MICSLIDER, TBM_SETPOS, TRUE, MicVol);
  2924. SendDlgItemMessage(hDlg, IDC_FADESLIDER, TBM_SETPOS, TRUE, FadeTime);
  2925. SendDlgItemMessage(hDlg, IDC_MICFADESLIDER, TBM_SETPOS, TRUE, MicFadeTime);
  2926. SendMessage(hDlg, WM_HSCROLL, 0, (LPARAM) GetDlgItem(hDlg, IDC_MUSSLIDER));
  2927. SendMessage(hDlg, WM_HSCROLL, 0, (LPARAM) GetDlgItem(hDlg, IDC_MUS2SLIDER));
  2928. SendMessage(hDlg, WM_HSCROLL, 0, (LPARAM) GetDlgItem(hDlg, IDC_MICSLIDER));
  2929. SendMessage(hDlg, WM_HSCROLL, 0, (LPARAM) GetDlgItem(hDlg, IDC_FADESLIDER));
  2930. SendMessage(hDlg, WM_HSCROLL, 0, (LPARAM) GetDlgItem(hDlg, IDC_MICFADESLIDER));
  2931. inWin = hDlg;
  2932. SetDeviceName();
  2933. SendMessage(hDlg, WM_COMMAND, MAKEWPARAM(IDC_DEVBOX, CBN_SELCHANGE), (LPARAM)GetDlgItem(hDlg,IDC_DEVBOX));
  2934. break;
  2935. }
  2936. case IDD_PANEL_LOGIN:
  2937. {
  2938. SendDlgItemMessageW(hDlg, IDC_PROTOCOL, CB_ADDSTRING, 0,(LPARAM)LocalisedString(IDS_AUTOMATIC, NULL, 0));
  2939. SendDlgItemMessage(hDlg, IDC_PROTOCOL, CB_SETITEMDATA, 0,(LPARAM)0);
  2940. SendDlgItemMessageW(hDlg, IDC_PROTOCOL, CB_ADDSTRING, 0,(LPARAM)LocalisedString(IDS_V2_MODE, NULL, 0));
  2941. SendDlgItemMessage(hDlg, IDC_PROTOCOL, CB_SETITEMDATA, 1,(LPARAM)2);
  2942. SendDlgItemMessageW(hDlg, IDC_PROTOCOL, CB_ADDSTRING, 0,(LPARAM)LocalisedString(IDS_V1_MODE, NULL, 0));
  2943. SendDlgItemMessage(hDlg, IDC_PROTOCOL, CB_SETITEMDATA, 2,(LPARAM)1);
  2944. SendDlgItemMessage(hDlg, IDC_TIMEOUT, EM_SETLIMITTEXT, 5, 0);
  2945. break;
  2946. }
  2947. case IDD_PANEL_DIRECTORY:
  2948. {
  2949. SendDlgItemMessage(hDlg, IDC_GENRES, BM_SETIMAGE, IMAGE_ICON,
  2950. (LPARAM)LoadImage(module.hDllInstance, MAKEINTRESOURCE(IDI_DOWNARROW),
  2951. IMAGE_ICON, 0, 0, LR_SHARED | LR_LOADTRANSPARENT | LR_CREATEDIBSECTION));
  2952. break;
  2953. }
  2954. }
  2955. }
  2956. return 1;
  2957. case WM_CLOSE:
  2958. {
  2959. if (hDlg == hMainDLG)
  2960. {
  2961. doQuit();
  2962. }
  2963. }
  2964. break;
  2965. case WM_USER:
  2966. {
  2967. if (lParam == nowPlayingID && wParam == 0) {
  2968. // Winamp Title handling
  2969. wchar_t title[1024] = {0},
  2970. next[1024] = {0},
  2971. song[1024] = {0},
  2972. artist[1024] = {0},
  2973. album[1024] = {0},
  2974. genre[1024] = {0},
  2975. comment[1024] = {0},
  2976. year[32] = {0},
  2977. tmp2[1024] = {0};
  2978. char buffer[1024] = {0},
  2979. buffer2[1024] = {0};
  2980. // winamp playlist length in tracks
  2981. int len = SendMessage(module.hwndParent, WM_WA_IPC, 0, IPC_GETLISTLENGTH);
  2982. int curpos = SendMessage(module.hwndParent, WM_WA_IPC, 0, IPC_GETLISTPOS);
  2983. int pos = curpos + 1;
  2984. int len2 = 0;
  2985. // get the current title
  2986. if (len >= 1) {
  2987. wcscpy_s(lastFile, MAX_PATH, (wchar_t*)SendMessage(module.hwndParent, WM_WA_IPC, curpos, IPC_GETPLAYLISTFILEW));
  2988. wcscpy_s(title, ARRAYSIZE(title), (wchar_t*)SendMessage(module.hwndParent, WM_WA_IPC, curpos, IPC_GETPLAYLISTTITLEW));
  2989. } else {
  2990. title[0] = lastFile[0] = 0;
  2991. }
  2992. // get the position of the next track if possible
  2993. pos = GetNextTracks(len, pos, next);
  2994. if (skipMetada == false) {
  2995. AddColItem(lastFile, 1, inWinWa, IDC_METALIST, 0);
  2996. GetFileMetaData(lastFile, L"title", song, ARRAYSIZE(song));
  2997. AddColItem((song && song[0] ? song : title), 1, inWinWa, IDC_METALIST, 1);
  2998. GetFileMetaData(lastFile, L"artist", artist, ARRAYSIZE(artist));
  2999. AddColItem((artist[0] ? artist : L"<emtpy>"), 1, inWinWa, IDC_METALIST, 2);
  3000. GetFileMetaData(lastFile, L"album", album, ARRAYSIZE(album));
  3001. AddColItem((album[0] ? album : L"<emtpy>"), 1, inWinWa, IDC_METALIST, 3);
  3002. GetFileMetaData(lastFile, L"genre", genre, ARRAYSIZE(genre));
  3003. AddColItem((genre[0] ? genre : L"<emtpy>"), 1, inWinWa, IDC_METALIST, 4);
  3004. GetFileMetaData(lastFile, L"year", year, ARRAYSIZE(year));
  3005. AddColItem((year[0] ? year : L"<emtpy>"), 1, inWinWa, IDC_METALIST, 5);
  3006. GetFileMetaData(lastFile, L"comment", comment, ARRAYSIZE(comment));
  3007. AddColItem((comment[0] ? comment : L"<emtpy>"), 1, inWinWa, IDC_METALIST, 6);
  3008. if (WASABI_API_MEMMGR && playingImage) {
  3009. WASABI_API_MEMMGR->sysFree(playingImage); playingImage = 0;
  3010. }
  3011. playingLength = 0;
  3012. playingType = 0x4100; // default in-case of issue
  3013. // attempt to get the type of the image, defaulting to jpeg for older versions
  3014. // as only on 5.64+ are we able to query Winamp properly for the artwork type
  3015. wchar_t* mimeType = 0, *uiType = L"jpeg";
  3016. if (GetWinampVersion(module.hwndParent) >= 0x5064)
  3017. {
  3018. LPVOID bits;
  3019. size_t len;
  3020. if (AGAVE_API_ALBUMART && AGAVE_API_ALBUMART->GetAlbumArtData(lastFile, L"cover", &bits, &len, &mimeType) == ALBUMART_SUCCESS) {
  3021. // make sure to free the original image after we've converted
  3022. playingImage = (ARGB32 *)bits;
  3023. playingLength = len;
  3024. wchar_t *ext = &mimeType[0];
  3025. if (ext && *ext) {
  3026. uiType = ext;
  3027. if (!wcsnicmp(ext, L"jpeg", 4) || !wcsnicmp(ext, L"jpg", 3)) {
  3028. playingType = 0x4100;
  3029. } else if (!wcsnicmp(ext, L"png", 3)) {
  3030. playingType = 0x4101;
  3031. } else if (!wcsnicmp(ext, L"bmp", 3)) {
  3032. playingType = 0x4102;
  3033. } else if (!wcsnicmp(ext, L"gif", 3)) {
  3034. playingType = 0x4103;
  3035. }
  3036. }
  3037. // update the current artwork on the winamp panel
  3038. // have to decode as we get the raw data normally
  3039. HWND artwork = GetDlgItem(inWinWa, IDC_ARTWORK);
  3040. HBITMAP bm = getBitmap(decompressImage(playingImage, playingLength, &playingImage_w, &playingImage_h), playingImage_w, playingImage_h);
  3041. HBITMAP bmold = (HBITMAP)SendMessage(artwork, STM_SETIMAGE, IMAGE_BITMAP, (LPARAM)bm);
  3042. if (bmold) DeleteObject(bmold);
  3043. InvalidateRect(artwork, NULL, TRUE);
  3044. }
  3045. } else {
  3046. playingImage_w = 0, playingImage_h = 0;
  3047. if (AGAVE_API_ALBUMART && AGAVE_API_ALBUMART->GetAlbumArt(lastFile, L"cover", &playingImage_w, &playingImage_h, &playingImage) == ALBUMART_SUCCESS) {
  3048. // make sure to free the original image after we've converted
  3049. ARGB32 *firstPlayingImage = playingImage;
  3050. // update the current artwork on the winamp panel
  3051. // no need to decode as it's already done by this
  3052. HWND artwork = GetDlgItem(inWinWa, IDC_ARTWORK);
  3053. HBITMAP bm = getBitmap(playingImage, playingImage_w, playingImage_h);
  3054. HBITMAP bmold = (HBITMAP)SendMessage(artwork, STM_SETIMAGE, IMAGE_BITMAP, (LPARAM)bm);
  3055. if (bmold) DeleteObject(bmold);
  3056. InvalidateRect(artwork, NULL, TRUE);
  3057. playingImage = writeImg(playingImage, playingImage_w, playingImage_h, &playingLength, L"jpeg");
  3058. WASABI_API_MEMMGR->sysFree(firstPlayingImage);
  3059. } else {
  3060. playingImage = 0;
  3061. }
  3062. }
  3063. wchar_t tmp3[1024] = {0};
  3064. if(playingImage)
  3065. {
  3066. StringCchPrintfW(tmp3, ARRAYSIZE(tmp3), L"Playing Artwork: Width=%d; Height=%d; Data=%s;",
  3067. playingImage_w, playingImage_h, sizeStr(playingLength));
  3068. // only use this on compatible Winamp installs where possible
  3069. wchar_t *mime = 0;
  3070. if (GetWinampVersion(module.hwndParent) >= 0x5064 &&
  3071. AGAVE_API_ALBUMART && AGAVE_API_ALBUMART->GetAlbumArtOrigin(lastFile, L"cover", &mime)) {
  3072. if (mime)
  3073. {
  3074. uiType = wcschr(mime, L'/');
  3075. if (uiType && *uiType)
  3076. {
  3077. uiType++;
  3078. }
  3079. }
  3080. } else {
  3081. if (mimeType)
  3082. {
  3083. uiType = wcschr(mimeType, L'/');
  3084. if (uiType && *uiType)
  3085. {
  3086. uiType++;
  3087. }
  3088. }
  3089. }
  3090. wchar_t buf[256] = {0};
  3091. StringCchPrintfW(buf, ARRAYSIZE(buf), LocalisedString(IDS_ARTWORK_SIZES, NULL, 0),
  3092. playingImage_w, playingImage_h, sizeStr(playingLength),
  3093. (uiType && *uiType ? uiType : mime));
  3094. SetDlgItemTextW(inWinWa, IDC_ARTWORK3, buf);
  3095. WASABI_API_MEMMGR->sysFree(mime);
  3096. }
  3097. else
  3098. {
  3099. // update the current artwork on the winamp panel
  3100. // by setting a generic image when nothing loaded
  3101. HWND artwork = GetDlgItem(inWinWa, IDC_ARTWORK);
  3102. HBITMAP bmold = (HBITMAP)SendMessage(artwork, STM_SETIMAGE, IMAGE_BITMAP, (LPARAM)0);
  3103. if (bmold) DeleteObject(bmold);
  3104. SetDlgItemTextW(inWinWa, IDC_ARTWORK3, L"");
  3105. StringCchPrintfW(tmp3, ARRAYSIZE(tmp3), L"Playing Artwork: Cleared;");
  3106. }
  3107. if (mimeType) WASABI_API_MEMMGR->sysFree(mimeType);
  3108. ShowWindowDlgItem(inWinWa, IDC_ARTWORK, (playingLength > 0));
  3109. ShowWindowDlgItem(inWinWa, IDC_ARTWORK2, (playingLength == 0));
  3110. ShowWindowDlgItem(inWinWa, IDC_ARTWORK3, (playingLength > 0));
  3111. CreateLogFileMessage(buffer2, tmp3, &len2);
  3112. }
  3113. // look at the playback queue so we can get the correct 'next song'
  3114. if (WASABI_API_SVC && !WASABI_API_QUEUEMGR) {
  3115. // due to loading orders its possible the queue won't have been loaded on init so check
  3116. ServiceBuild(WASABI_API_SVC, WASABI_API_QUEUEMGR, QueueManagerApiGUID);
  3117. }
  3118. std::vector<std::wstring> nextList;
  3119. std::vector<int> nextListIdx;
  3120. UpdateNextTracks(next, pos, nextListIdx, nextList);
  3121. StringCchPrintfW(tmp2, ARRAYSIZE(tmp2), L"Metadata: Artist=%s; Album=%s; Genre=%s; Year=%s; Comment=%s; Title=%s;",
  3122. artist, album, genre, year, comment, (song && song[0] ? song : title));
  3123. len = 0;
  3124. CreateLogFileMessage(buffer, tmp2, &len);
  3125. // update the title cache for all of the encoders otherwise we might fail, etc
  3126. for (int i = 0; i < NUM_OUTPUTS; i++) {
  3127. MY_T_OUTPUT *Out = &Output[i];
  3128. if (Out->nextTrackLog) {
  3129. WriteNextTracks(i, module.hwndParent, nextListIdx, nextList, !!Out->nextTrackLogXML);
  3130. }
  3131. if (WaitForSingleObject(Enc_mutex[Out->Encoder], INFINITE) == WAIT_OBJECT_0) {
  3132. Encoder[i].UpdateTitleCache(title, nextList, song, album, artist, genre, comment, year, Out->Handle, !!Out->NextTitles);
  3133. ReleaseMutex(Enc_mutex[Out->Encoder]);
  3134. }
  3135. // skip this all if the mode is not enabled and only in SC2 mode
  3136. if ((LOBYTE(Out->Config.protocol) != 1) && Out->useArt) {
  3137. // this will only update generally on first connection
  3138. if (Out->useStreamArt && streamImage[i] == (ARGB32 *)-1) {
  3139. UpdateStreamAlbumArt(Out->Handle, i, Out->stationArtPath, !!Out->useStreamArt);
  3140. }
  3141. // this will update against what is read from the playing
  3142. if (Out->usePlayingArt) {
  3143. UpdatePlayingAlbumArt(Out->Handle, i, Out->useArt && Out->usePlayingArt);
  3144. }
  3145. }
  3146. // save the updated metadata to the log file (if enabled)
  3147. if (Out->Logging && logFiles[i] != INVALID_HANDLE_VALUE) {
  3148. DWORD written = 0;
  3149. WriteFile(logFiles[i], buffer, len, &written, 0);
  3150. WriteFile(logFiles[i], buffer2, len2, &written, 0);
  3151. }
  3152. }
  3153. }
  3154. }
  3155. break;
  3156. case WM_TIMER:
  3157. {
  3158. if (wParam == IDD_MAIN || wParam == IDD_INPUT) {
  3159. if (VU.update || VU.update != VU.lastUpdate)
  3160. {
  3161. UpdateVUMeters();
  3162. }
  3163. }
  3164. if (wParam == 1234) { // input timer
  3165. if (InputDevice == 1) {
  3166. for (int i = 0; i < NUM_BUFFERS; i++) {
  3167. if (Soundcard.isFilled(last_buffer)) {
  3168. short *buffer = Soundcard[last_buffer];
  3169. int scardsmps = Soundcard.getNumSamples(last_buffer);
  3170. int numsamps = scardsmps * InputConfig.nch;
  3171. if (!VU.update) {
  3172. for (int j = 0; j < numsamps; j++) {
  3173. if (VU.vu_l < buffer[j]) VU.vu_l = buffer[j];
  3174. if (LineInputAttribs[Input_CurSelPos].nch == 2) {
  3175. if (VU.vu_r < buffer[j + 1]) VU.vu_r = buffer[j + 1];
  3176. j++;
  3177. }
  3178. }
  3179. if (LineInputAttribs[Input_CurSelPos].nch == 1) VU.vu_r = VU.vu_l;
  3180. VU.update = 1;
  3181. }
  3182. if (WaitForSingleObject(cf_mutex, INFINITE) == WAIT_OBJECT_0) {
  3183. Crossfader->put(buffer, scardsmps);
  3184. ReleaseMutex(cf_mutex);
  3185. }
  3186. Soundcard.cycleBuffer(last_buffer++);
  3187. if (last_buffer >= NUM_BUFFERS) last_buffer = 0;
  3188. }
  3189. }
  3190. }
  3191. } else if (wParam == IDD_MAIN || wParam == IDD_CONNECTION ||
  3192. wParam == IDD_INPUT || wParam == IDD_ABOUT) {
  3193. wchar_t title[1024] = {0};
  3194. wchar_t next[1024] = {0};
  3195. int states[NUM_OUTPUTS] = {OUT_ERROR,OUT_ERROR,OUT_ERROR,OUT_ERROR,OUT_ERROR};
  3196. for (int i = 0; i < NUM_OUTPUTS; i++) {
  3197. wchar_t tmp[1024] = {0};
  3198. static wchar_t old_tmp[NUM_ENCODERS][1024] = {0};
  3199. MY_T_OUTPUT *Out = &Output[i];
  3200. SHOUTCAST_OUTPUT *Enc = Out->Encoder != -1 ? &Encoder[Out->Encoder] : NULL;
  3201. bool encoder_ok = false;
  3202. if (Enc) {
  3203. C_ENCODER *Encoder = Enc->GetEncoder();
  3204. if (Encoder) {
  3205. if (strcmp(Encoder->GetName(), "MP3 Encoder") == 0) {
  3206. encoder_ok = (libinst != NULL);
  3207. } else {
  3208. encoder_ok = true;
  3209. }
  3210. }
  3211. }
  3212. lastEnable[i] = (encoder_ok && Out->Config.Address[0] && Out->Config.Password[0] &&
  3213. stationNameAllowed(Out->Config.Description));
  3214. if (Out->Encoder == -1 || Out->Handle == -1) {
  3215. LocalisedString(IDS_NOT_CONNECTED, tmp, ARRAYSIZE(tmp));
  3216. if (wParam == IDD_CONNECTION && i == Connection_CurSelPos) {
  3217. GetDlgItemTextW(out_wnd[3].hWnd, IDC_TITLE, title, sizeof (title) / sizeof (wchar_t));
  3218. GetDlgItemTextW(out_wnd[3].hWnd, IDC_NEXT, next, sizeof (next) / sizeof (wchar_t));
  3219. }
  3220. } else {
  3221. if (WaitForSingleObject(Enc_mutex[Out->Encoder], INFINITE) == WAIT_OBJECT_0) {
  3222. T_OUTPUT_INFO *Info = Enc->GetOutputInfo(Out->Handle);
  3223. if (title != NULL && next != NULL && Info != NULL) {
  3224. if (Info->Title)
  3225. {
  3226. free(Info->Title);
  3227. }
  3228. Info->Title = _wcsdup(title);
  3229. }
  3230. states[i] = Enc->GetState(Out->Handle);
  3231. switch (states[i]) {
  3232. case OUT_ERROR:
  3233. {
  3234. LocalisedString(IDS_ERROR, tmp, ARRAYSIZE(tmp));
  3235. }
  3236. break;
  3237. case OUT_DISCONNECTED:
  3238. {
  3239. if (Info->Succeeded < 0) {
  3240. if (Info->ErrorMsg && Info->ErrorMsg[0]) {
  3241. // if an error is reported, try to give a user-friendly error message
  3242. if (!strcmp("NAK:Deny", Info->ErrorMsg))
  3243. // localised Password error
  3244. LocalisedString(IDS_PASS_ERROR, tmp, ARRAYSIZE(tmp));
  3245. else if (!strcmp("CipherFail",Info->ErrorMsg))
  3246. // localised cipher error
  3247. LocalisedString(IDS_CIPHER_ERROR, tmp, ARRAYSIZE(tmp));
  3248. else if (!strcmp("BitrateError",Info->ErrorMsg))
  3249. // localised bitrate error (not allowed / not supported)
  3250. LocalisedString(IDS_BITRATE_ERROR, tmp, ARRAYSIZE(tmp));
  3251. else if (!strcmp("StreamID",Info->ErrorMsg))
  3252. // localised stream moved error
  3253. LocalisedString(IDS_STREAMID_ERROR, tmp, ARRAYSIZE(tmp));
  3254. else if (!strcmp("StreamMoved",Info->ErrorMsg))
  3255. LocalisedString(IDS_STREAM_MOVED_ERROR, tmp, ARRAYSIZE(tmp));
  3256. else if (!strcmp("VersionError",Info->ErrorMsg))
  3257. // localised version error
  3258. LocalisedString(IDS_VERSION_ERROR, tmp, ARRAYSIZE(tmp));
  3259. else if (!strcmp("Blocked",Info->ErrorMsg))
  3260. // localised blocked error
  3261. LocalisedString(IDS_BLOCKED_ERROR, tmp, ARRAYSIZE(tmp));
  3262. else if (!strcmp("InUse",Info->ErrorMsg))
  3263. // localised in use error
  3264. LocalisedString(IDS_IN_USE_ERROR, tmp, ARRAYSIZE(tmp));
  3265. else if (!strcmp("ParseError",Info->ErrorMsg))
  3266. // localised parse error
  3267. LocalisedString(IDS_PARSE_ERROR, tmp, ARRAYSIZE(tmp));
  3268. else
  3269. // non localised dynamic nak error
  3270. StringCchPrintfW(tmp, ARRAYSIZE(tmp), L"%hs", Info->ErrorMsg);
  3271. } else {
  3272. // localised Password error
  3273. LocalisedString(IDS_PASS_ERROR, tmp, ARRAYSIZE(tmp));
  3274. }
  3275. Out->Config.AutoRecon = 0;
  3276. } else {
  3277. if (Info->last_state == OUT_RECV_CIPHER ||
  3278. Info->last_state == OUT_REQUEST_CIPHER) {
  3279. StringCchPrintfW(tmp, ARRAYSIZE(tmp), LocalisedString(IDS_ENABLE_OTHER_MODE, NULL, 0), (Info->last_state == OUT_RECV_CIPHER ? 1 : 2));
  3280. } else {
  3281. LocalisedString((lastEnable[i] ? IDS_NOT_CONNECTED : IDS_NOT_CONFIGURED), tmp, ARRAYSIZE(tmp));
  3282. }
  3283. lastSec[i] = 0;
  3284. }
  3285. }
  3286. break;
  3287. case OUT_CONNECT:
  3288. {
  3289. if ((clock() - Info->ConnectionTime) / CLOCKS_PER_SEC < 1) {
  3290. StringCchPrintfW(tmp, ARRAYSIZE(tmp), LocalisedString(IDS_RECONNECTING_X, NULL, 0), 1);
  3291. } else {
  3292. LocalisedString(IDS_CONNECTING, tmp, ARRAYSIZE(tmp));
  3293. }
  3294. }
  3295. break;
  3296. case OUT_REQUEST_CIPHER:
  3297. {
  3298. LocalisedString(IDS_SEND_CIPHER_REQUEST, tmp, ARRAYSIZE(tmp));
  3299. }
  3300. break;
  3301. case OUT_RECV_CIPHER:
  3302. {
  3303. LocalisedString(IDS_CIPHER_RESPONSE_RECEIVED, tmp, ARRAYSIZE(tmp));
  3304. }
  3305. break;
  3306. case OUT_SENDAUTH:
  3307. {
  3308. LocalisedString(IDS_SENDING_AUTH, tmp, ARRAYSIZE(tmp));
  3309. }
  3310. break;
  3311. case OUT_RECVAUTHRESPONSE:
  3312. {
  3313. LocalisedString(IDS_RECEIVING_AUTH_RESPONSE, tmp, ARRAYSIZE(tmp));
  3314. }
  3315. break;
  3316. case OUT_SEND_MIME:
  3317. {
  3318. LocalisedString(IDS_SENDING_CONTENT_TYPE, tmp, ARRAYSIZE(tmp));
  3319. }
  3320. break;
  3321. case OUT_RECV_MIME:
  3322. {
  3323. LocalisedString(IDS_RESPONSE_RECEIVED, tmp, ARRAYSIZE(tmp));
  3324. }
  3325. break;
  3326. case OUT_SEND_BITRATE:
  3327. {
  3328. LocalisedString(IDS_SENDING_BITRATE, tmp, ARRAYSIZE(tmp));
  3329. }
  3330. break;
  3331. case OUT_RECV_BITRATE:
  3332. {
  3333. LocalisedString(IDS_RESPONSE_RECEIVED, tmp, ARRAYSIZE(tmp));
  3334. }
  3335. break;
  3336. case OUT_SEND_BUFSIZE:
  3337. {
  3338. LocalisedString(IDS_SEND_BUF_SIZE, tmp, ARRAYSIZE(tmp));
  3339. }
  3340. break;
  3341. case OUT_RECV_BUFSIZE:
  3342. {
  3343. LocalisedString(IDS_RESPONSE_RECEIVED, tmp, ARRAYSIZE(tmp));
  3344. }
  3345. break;
  3346. case OUT_SEND_MAX:
  3347. {
  3348. LocalisedString(IDS_SEND_MAX_PAYLOAD_SIZE, tmp, ARRAYSIZE(tmp));
  3349. }
  3350. break;
  3351. case OUT_RECV_MAX:
  3352. {
  3353. LocalisedString(IDS_RESPONSE_RECEIVED, tmp, ARRAYSIZE(tmp));
  3354. }
  3355. break;
  3356. case OUT_SENDYP:
  3357. {
  3358. LocalisedString(IDS_SEND_YP_INFO, tmp, ARRAYSIZE(tmp));
  3359. }
  3360. break;
  3361. case OUT_SEND_INITFLUSH:
  3362. {
  3363. LocalisedString(IDS_SEND_FLUSH, tmp, ARRAYSIZE(tmp));
  3364. }
  3365. break;
  3366. case OUT_RECV_INITFLUSH:
  3367. {
  3368. LocalisedString(IDS_RESPONSE_RECEIVED, tmp, ARRAYSIZE(tmp));
  3369. }
  3370. break;
  3371. case OUT_SEND_INITSTANDBY:
  3372. {
  3373. LocalisedString(IDS_SEND_STANDBY, tmp, ARRAYSIZE(tmp));
  3374. }
  3375. break;
  3376. case OUT_RECV_INITSTANDBY:
  3377. {
  3378. LocalisedString(IDS_RESPONSE_RECEIVED, tmp, ARRAYSIZE(tmp));
  3379. }
  3380. break;
  3381. /*case OUT_SEND_INTRO:
  3382. {
  3383. LocalisedString(IDS_SEND_INTRO_FILE, tmp, ARRAYSIZE(tmp));
  3384. }
  3385. break;
  3386. case OUT_RECV_INTRO:
  3387. {
  3388. LocalisedString(IDS_RESPONSE_RECEIVED, tmp, ARRAYSIZE(tmp));
  3389. }
  3390. break;
  3391. case OUT_SEND_BACKUP:
  3392. {
  3393. LocalisedString(IDS_SEND_BACKUP_FILE, tmp, ARRAYSIZE(tmp));
  3394. }
  3395. break;
  3396. case OUT_RECV_BACKUP:
  3397. {
  3398. LocalisedString(IDS_RESPONSE_RECEIVED, tmp, ARRAYSIZE(tmp));
  3399. }
  3400. break;*/
  3401. case OUT_SEND_ARTWORK:
  3402. case OUT_SEND_METADATA:
  3403. break;
  3404. case OUT_SENDCONTENT:
  3405. {
  3406. time_t time_value = time(NULL) - Info->ConnectedAt;
  3407. long hour = (long)(time_value/3600);
  3408. long min = (time_value/60)%60;
  3409. long sec = time_value%60;
  3410. static wchar_t format[256];
  3411. if (!format[0]) LocalisedString(IDS_SENT_X, format, ARRAYSIZE(format));
  3412. StringCchPrintfW(tmp, ARRAYSIZE(tmp), format, hour, min, sec, sizeStr(Info->BytesSent));
  3413. lastSec[i] = sec;
  3414. // do this to filter out some of the log
  3415. // events so it'll only happen every second
  3416. if (lastSec[i] == sec - 1) {
  3417. secChanged[i] = true;
  3418. }
  3419. }
  3420. break;
  3421. case OUT_DISCONNECT:
  3422. {
  3423. LocalisedString(IDS_DISCONNECTING, tmp, ARRAYSIZE(tmp));
  3424. }
  3425. break;
  3426. case OUT_RECONNECT:
  3427. {
  3428. if (Info->Reconnect) {
  3429. int seconds = Info->ReconnectTime - ((clock() - Info->ConnectionTime) / CLOCKS_PER_SEC);
  3430. if (seconds > 0) {
  3431. StringCchPrintfW(tmp, ARRAYSIZE(tmp), LocalisedString(IDS_RECONNECTING_X, NULL, 0), seconds);
  3432. } else {
  3433. if (Info->Switching) {
  3434. StringCchPrintfW(tmp, ARRAYSIZE(tmp), LocalisedString(IDS_SWITCHING_PROTOCOL, NULL, 0),
  3435. (Info->Switching == 2 ? 2 : 1), (Info->Switching == 2 ? 1 : 2));
  3436. } else {
  3437. StringCchPrintfW(tmp, ARRAYSIZE(tmp), LocalisedString(IDS_RECONNECTING_X, NULL, 0), seconds);
  3438. }
  3439. }
  3440. } else {
  3441. if (Info->Switching) {
  3442. StringCchPrintfW(tmp, ARRAYSIZE(tmp), LocalisedString(IDS_SWITCHING_PROTOCOL, NULL, 0),
  3443. (Info->Switching == 2 ? 2 : 1), (Info->Switching == 2 ? 1 : 2));
  3444. } else {
  3445. LocalisedString(IDS_DISCONNECTING, tmp, ARRAYSIZE(tmp));
  3446. }
  3447. }
  3448. }
  3449. break;
  3450. case OUT_TITLESENDUPDATE:
  3451. {
  3452. LocalisedString(IDS_SEND_TITLE_UPDATE, tmp, ARRAYSIZE(tmp));
  3453. }
  3454. break;
  3455. }
  3456. if (Out->AutoConnect && states[i] == OUT_DISCONNECTED) {
  3457. Enc->ConnectOutput(Out->Handle);
  3458. }
  3459. ReleaseMutex(Enc_mutex[Out->Encoder]);
  3460. }
  3461. }
  3462. // output log messages to the log files if enabled
  3463. // but filter things a bit more with the sent state
  3464. if (tmp[0] && wcsnicmp(old_tmp[i], tmp, ARRAYSIZE(tmp))) {
  3465. if (Out->Logging && logFiles[i] != INVALID_HANDLE_VALUE) {
  3466. if (states[i] != OUT_SENDCONTENT || (states[i] == OUT_SENDCONTENT && secChanged[i] == true)) {
  3467. DWORD written = 0;
  3468. int len = 0;
  3469. char buffer[1024];
  3470. if (states[i] == OUT_CONNECT) {
  3471. wchar_t tmp2[2048] = {0};
  3472. int protocol = (LOBYTE(Out->Config.protocol) != 1 ? 2 : 1);
  3473. StringCchPrintfW(tmp2, ARRAYSIZE(tmp2),
  3474. L"Connecting to... Server: %hs; Port: %d; Mode: v%d; Stream ID: %hs; DJ / User ID: %hs",
  3475. Out->Config.Address, Out->Config.Port, protocol,
  3476. (protocol == 1 ? "n/a" : Out->Config.StationID),
  3477. (!Out->Config.UserID[0] ? "n/a" : Out->Config.UserID));
  3478. CreateLogFileMessage(buffer, tmp2, &len);
  3479. WriteFile(logFiles[i], buffer, len, &written, 0);
  3480. } else {
  3481. CreateLogFileMessage(buffer, tmp, &len);
  3482. WriteFile(logFiles[i], buffer, len, &written, 0);
  3483. }
  3484. }
  3485. }
  3486. secChanged[i] = false;
  3487. }
  3488. // update summary and output page view and text states as applicable
  3489. if (wParam == IDD_MAIN ||
  3490. (wParam == IDD_CONNECTION && i == Connection_CurSelPos)) {
  3491. // update status text for the output being processed
  3492. if (tmp[0]) {
  3493. if (wParam == IDD_CONNECTION && i == Connection_CurSelPos) {
  3494. SetDlgItemTextW(wnd[1].hWnd, IDC_STATUS, tmp);
  3495. }
  3496. AddColItem(tmp, 2, wnd[0].hWnd, IDC_OUTPUTSTATUS, i);
  3497. }
  3498. bool encoder_ok = false;
  3499. if (Enc) {
  3500. C_ENCODER *Encoder = Enc->GetEncoder();
  3501. if (Encoder) {
  3502. if (strcmp(Encoder->GetName(), "MP3 Encoder") == 0) {
  3503. encoder_ok = (libinst != NULL);
  3504. } else {
  3505. encoder_ok = true;
  3506. }
  3507. }
  3508. }
  3509. // update the playback buttons on the summary page
  3510. int mode = (Out->Config.Address[0] ? (Out->Config.Password[0] ?
  3511. (stationNameAllowed(Out->Config.Description) ?
  3512. (encoder_ok ? (states[i] == OUT_DISCONNECTED ? 0 :
  3513. states[i] == OUT_DISCONNECT ? 1 : states[i] == OUT_RECONNECT ? 7 : 2) : 6) : 5) : 4) : 3);
  3514. // used to limit the amount of processing which is done for this to keep updates to just what is needed
  3515. if (lastMode[i] == -1 || lastMode[i] != mode) {
  3516. int image_id[] = {IDI_PLAY, IDI_KILL, IDI_STOP, IDI_PLAY, IDI_PLAY, IDI_PLAY, IDI_PLAY, IDI_STOP};
  3517. // do checks to see if we need to update the error state of the tab items
  3518. int oldMode = lastMode[i];
  3519. lastMode[i] = mode;
  3520. RECT r = {0};
  3521. if (IsWindow(outTabWnd)) {
  3522. int index[] = {0, 0, 1, 2};
  3523. if (lastMode[i] >= 3 && lastMode[i] <= 6) {
  3524. TabCtrl_GetItemRect(outTabWnd, index[(lastMode[i] - 3)], &r);
  3525. InvalidateRect(outTabWnd, &r, 0);
  3526. }
  3527. if (oldMode >= 3 && oldMode <= 6) {
  3528. TabCtrl_GetItemRect(outTabWnd, index[(oldMode - 3)], &r);
  3529. InvalidateRect(outTabWnd, &r, 0);
  3530. }
  3531. }
  3532. TabCtrl_GetItemRect(GetDlgItem(hMainDLG, IDC_TAB), 1, &r);
  3533. InvalidateRect(GetDlgItem(hMainDLG, IDC_TAB), &r, 0);
  3534. // control the button states on the pages
  3535. EnableWindow(buttonWnd[i], lastEnable[i]);
  3536. EnableWindowDlgItem(wnd[1].hWnd, IDC_CONNECT, lastEnable[i]);
  3537. EnableWindowDlgItem(wnd[1].hWnd, IDC_AUTOCONNECT, lastEnable[i]);
  3538. SendMessage(buttonWnd[i], BM_SETIMAGE, IMAGE_ICON,
  3539. (LPARAM)LoadImage(module.hDllInstance, MAKEINTRESOURCE(image_id[mode]),
  3540. IMAGE_ICON, 0, 0, LR_SHARED | LR_LOADTRANSPARENT | LR_CREATEDIBSECTION));
  3541. // control the 'connect' button to be disabled when no encoder / no password / invalid station name
  3542. if (i == Connection_CurSelPos) {
  3543. int button_id[] = {IDS_CONNECT, IDS_KILL, IDS_DISCONNECT, IDS_SET_SERVER, IDS_SET_PASSWORD, IDS_CHANGE_NAME, IDS_SET_ENCODER, IDS_ABORT};
  3544. SetDlgItemTextW(wnd[1].hWnd, IDC_CONNECT, LocalisedString(button_id[mode], NULL, 0));
  3545. LockOptionControls((states[i] == OUT_DISCONNECTED && Out->Handle != -1));
  3546. InvalidateRect(GetDlgItem(out_wnd[0].hWnd, IDC_ADDRESS_HEADER), 0, 0);
  3547. InvalidateRect(GetDlgItem(out_wnd[0].hWnd, IDC_PASSWORD_HEADER), 0, 0);
  3548. InvalidateRect(GetDlgItem(out_wnd[1].hWnd, IDC_NAME_HEADER), 0, 0);
  3549. InvalidateRect(GetDlgItem(out_wnd[2].hWnd, IDC_ENCODER_HEADER), 0, 0);
  3550. }
  3551. }
  3552. // update the title set
  3553. if (Out->AutoTitle) SetDlgItemTextW(out_wnd[0].hWnd, IDC_TITLE, title);
  3554. }
  3555. // preserve the last status message for filtering of the log output, etc
  3556. if (tmp[0]) wcsncpy(old_tmp[i], tmp, 1024);
  3557. }
  3558. } else if (wParam == 1337) { // stream title update
  3559. KillTimer(hDlg, wParam);
  3560. PostMessage(hMainDLG, WM_USER, 0, nowPlayingID);
  3561. } else if (wParam == 2234) { // fade (music)
  3562. if (InputDevice) {
  3563. clock_t MusCurTime = clock();
  3564. if (FadeStartTime == 0) {
  3565. FadeStartTime = MusCurTime;
  3566. }
  3567. MusCurTime -= FadeStartTime;
  3568. int micsrc = Input_Device_ID >= 1 ? MIXERLINE_COMPONENTTYPE_SRC_LINE : MIXERLINE_COMPONENTTYPE_SRC_MICROPHONE;
  3569. if (MusCurTime < (FadeTime * 100)) {
  3570. int musvol = FadeOut ? (MusVol * 10)+((((Mus2Vol - MusVol)*10) * MusCurTime) / (FadeTime * 100)) : (Mus2Vol * 10)+((((MusVol - Mus2Vol)*10) * MusCurTime) / (FadeTime * 100));
  3571. setlev(MIXERLINE_COMPONENTTYPE_SRC_WAVEOUT, musvol);
  3572. } else {
  3573. if (FadeOut) {
  3574. setlev(MIXERLINE_COMPONENTTYPE_SRC_WAVEOUT, Mus2Vol * 10);
  3575. } else {
  3576. setlev(MIXERLINE_COMPONENTTYPE_SRC_WAVEOUT, MusVol * 10);
  3577. }
  3578. FadeStartTime = 0;
  3579. KillTimer(hDlg, wParam);
  3580. // kill captured device
  3581. #ifdef CAPTURE_TESTING
  3582. if (!FadeOut) {// end_capture();
  3583. if (pPlayer != NULL) {
  3584. pPlayer->Stop();
  3585. delete pPlayer;
  3586. pPlayer = NULL;
  3587. }
  3588. }
  3589. #endif
  3590. }
  3591. }
  3592. } else if (wParam == 2235) { // fade (capture device)
  3593. if (InputDevice) {
  3594. clock_t MicCurTime = clock();
  3595. if (MicFadeStartTime == 0) {
  3596. MicFadeStartTime = MicCurTime;
  3597. }
  3598. MicCurTime -= MicFadeStartTime;
  3599. int micsrc = Input_Device_ID >= 1 ? MIXERLINE_COMPONENTTYPE_SRC_LINE : MIXERLINE_COMPONENTTYPE_SRC_MICROPHONE;
  3600. if (MicCurTime < (MicFadeTime * 100)) {
  3601. int micvol = FadeOut ? ((MicVol * 10) * MicCurTime) / (MicFadeTime * 100) : (MicVol * 10)+(((MicVol*-10) * MicCurTime) / (MicFadeTime * 100));
  3602. setlev(micsrc, micvol);
  3603. } else {
  3604. if (FadeOut) {
  3605. setlev(micsrc, MicVol * 10);
  3606. } else {
  3607. setlev(micsrc, 0);
  3608. }
  3609. MicFadeStartTime = 0;
  3610. KillTimer(hDlg, wParam);
  3611. // kill captured device
  3612. #ifdef CAPTURE_TESTING
  3613. if (!FadeOut) {// end_capture();
  3614. if (pPlayer != NULL) {
  3615. pPlayer->Stop();
  3616. delete pPlayer;
  3617. pPlayer = NULL;
  3618. }
  3619. }
  3620. #endif
  3621. }
  3622. }
  3623. } else if (wParam == 666) { // INI save timer
  3624. if (!ini_modified) break;
  3625. ini_modified = 0;
  3626. int i;
  3627. WritePrivateProfileInt("ofnidx", lastFilterIndex, 0, 0);
  3628. WritePrivateProfileInt("CurTab", curtab, 0, 0);
  3629. WritePrivateProfileInt("Connection_CurSelPos", Connection_CurSelPos, 0, 0);
  3630. WritePrivateProfileInt("Connection_CurTab", curouttab, 0, 0);
  3631. WritePrivateProfileInt("Encoder_CurSelPos", Encoder_CurSelPos, 0, 0);
  3632. WritePrivateProfileInt("Input_CurSelPos", Input_CurSelPos, 0, 0);
  3633. WritePrivateProfileInt("InputDevice", InputDevice, 0, 0);
  3634. WritePrivateProfileInt("MusicVolume", MusVol, 0, 0);
  3635. WritePrivateProfileInt("BGMusicVolume", Mus2Vol, 0, 0);
  3636. WritePrivateProfileInt("MicVolume", MicVol, 0, 0);
  3637. WritePrivateProfileInt("PTT_FT", FadeTime, 0, 0);
  3638. WritePrivateProfileInt("PTT_MicFT", MicFadeTime, 0, 0);
  3639. WritePrivateProfileInt("PTT_MicInput", Input_Device_ID, 0, 0);
  3640. WritePrivateProfileInt("PTT_Restore", Restore_PTT, 0, 0);
  3641. if (!IsIconic(hDlg)) {
  3642. WritePrivateProfileInt("WindowLeft", mainrect.left, 0, 0);
  3643. WritePrivateProfileInt("WindowTop", mainrect.top, 0, 0);
  3644. }
  3645. for (i = 0; i < NUM_ENCODERS; i++) {
  3646. int Type = 0;
  3647. char name[32];
  3648. StringCchPrintfA(name, ARRAYSIZE(name), "Encoder %u", i + 1);
  3649. if (WaitForSingleObject(Enc_mutex[i], INFINITE) == WAIT_OBJECT_0) {
  3650. C_ENCODER *Enc = Encoder[i].GetEncoder();
  3651. if (Enc) {
  3652. if (strcmp(Enc->GetName(), "MP3 Encoder") == 0) {
  3653. int infosize = sizeof (T_ENCODER_MP3_INFO);
  3654. T_ENCODER_MP3_INFO *EncInfo = (T_ENCODER_MP3_INFO *) Enc->GetExtInfo(&infosize);
  3655. WritePrivateProfileInt("BitRate", EncInfo->output_bitRate, name, 0);
  3656. WritePrivateProfileInt("SampleRate", EncInfo->output_sampleRate, name, 0);
  3657. WritePrivateProfileInt("NumChannels", EncInfo->output_numChannels, name, 0);
  3658. WritePrivateProfileInt("QualityMode", EncInfo->QualityMode, name, 0);
  3659. Type = 1;
  3660. } else if (strcmp(Enc->GetName(), "Fraunhofer Encoder") == 0) { // FHG AAC
  3661. ((C_ENCODER_NSV*) Enc)->FillConfFile(IniName, name);
  3662. Type = 2;
  3663. } else if (strcmp(Enc->GetName(), "AAC+ Encoder") == 0) { // AAC+
  3664. ((C_ENCODER_NSV*) Enc)->FillConfFile(IniName, name);
  3665. Type = 2;
  3666. }
  3667. #ifdef USE_OGG
  3668. else if (strcmp(Enc->GetName(), "OGG Vorbis Encoder") == 0) { // OGG
  3669. ((C_ENCODER_NSV*) Enc)->FillConfFile(IniName, name);
  3670. Type = 4;
  3671. }
  3672. #endif
  3673. }
  3674. ReleaseMutex(Enc_mutex[i]);
  3675. }
  3676. WritePrivateProfileInt("Type", Type, name, 0);
  3677. }
  3678. for (i = 0; i < NUM_OUTPUTS; i++) {
  3679. T_OUTPUT_CONFIG *Out = &Output[i].Config;
  3680. WritePrivateProfileString(Out->Name, "Address", Out->Address, IniName);
  3681. WritePrivateProfileInt("Port", Out->Port, Out->Name, 0);
  3682. WritePrivateProfileString(Out->Name, "UserID", Out->UserID, IniName);
  3683. WritePrivateProfileString(Out->Name, "StreamID", Out->StationID, IniName);
  3684. WritePrivateProfileString(Out->Name, "Password", Out->Password, IniName);
  3685. // disabled saving of this as it defeats the point of setting it on load
  3686. // (as it's otherwise over-written with the correct value from the server)
  3687. //WritePrivateProfileString(Out->Name, "Cipherkey", Out->cipherkey, IniName);
  3688. WritePrivateProfileString(Out->Name, "Description", Out->Description, IniName);
  3689. WritePrivateProfileString(Out->Name, "URL", Out->ServerURL, IniName);
  3690. WritePrivateProfileString(Out->Name, "Genre3", Out->Genre, IniName);
  3691. WritePrivateProfileString(Out->Name, "AIM", Out->AIM, IniName);
  3692. WritePrivateProfileString(Out->Name, "ICQ", Out->ICQ, IniName);
  3693. WritePrivateProfileString(Out->Name, "IRC", Out->IRC, IniName);
  3694. WritePrivateProfileInt("Public", Out->Public ? 1 : 0, Out->Name, 0);
  3695. WritePrivateProfileInt("AutoRecon", Out->AutoRecon ? 1 : 0, Out->Name, 0);
  3696. WritePrivateProfileInt("ReconTime", Out->ReconTime ? Out->ReconTime : 1, Out->Name, 0);
  3697. WritePrivateProfileInt("doTitleUpdate", Out->doTitleUpdate ? 1 : 0, Out->Name, 0);
  3698. WritePrivateProfileString(Out->Name, "now", Out->Now, IniName);
  3699. WritePrivateProfileString(Out->Name, "next", Out->Next, IniName);
  3700. WritePrivateProfileInt("AutoTitle", Output[i].AutoTitle ? 1 : 0, Out->Name, 0);
  3701. WritePrivateProfileInt("AutoConnect", Output[i].AutoConnect ? 1 : 0, Out->Name, 0);
  3702. WritePrivateProfileInt("Logging", Output[i].Logging ? 1 : 0, Out->Name, 0);
  3703. WritePrivateProfileInt("LogCOS", Output[i].LogCOS ? 1 : 0, Out->Name, 0);
  3704. WritePrivateProfileInt("NextTitles", Output[i].NextTitles ? 1 : 0, Out->Name, 0);
  3705. WritePrivateProfileInt("Protocol", Output[i].Config.protocol, Out->Name, 0);
  3706. WritePrivateProfileInt("nextTrackLog", Output[i].nextTrackLog ? 1 : 0, Out->Name, 0);
  3707. WritePrivateProfileInt("nextTrackLogXML", Output[i].nextTrackLogXML ? 1 : 0, Out->Name, 0);
  3708. WritePrivateProfileString(Out->Name, "nextTrackPath", ConvertToUTF8(Output[i].nextTrackPath), IniName);
  3709. WritePrivateProfileInt("useArt", Output[i].useArt ? 1 : 0, Out->Name, 0);
  3710. WritePrivateProfileInt("usePlayingArt", Output[i].usePlayingArt ? 1 : 0, Out->Name, 0);
  3711. WritePrivateProfileInt("useStreamArt", Output[i].useStreamArt ? 1 : 0, Out->Name, 0);
  3712. WritePrivateProfileString(Out->Name, "stationArtPath", ConvertToUTF8(Output[i].stationArtPath), IniName);
  3713. WritePrivateProfileInt("saveEncoded", Output[i].saveEncoded ? 1 : 0, Out->Name, 0);
  3714. WritePrivateProfileString(Out->Name, "saveEncodedPath", ConvertToUTF8(Output[i].saveEncodedPath), IniName);
  3715. WritePrivateProfileInt("Encoder", Output[i].Encoder, Out->Name, 0);
  3716. }
  3717. }
  3718. }
  3719. break;
  3720. case WM_SHOWWINDOW:
  3721. {
  3722. if (IsWindow(hDlg) && hDlg == hMainDLG && wnd[curtab].timer_freq != 0) {
  3723. KillTimer(hDlg, wnd[curtab].id);
  3724. SetTimer(hDlg, wnd[curtab].id, wnd[curtab].timer_freq, NULL);
  3725. } else if (IsWindow(hDlg) && hDlg == wnd[2].hWnd && in_wnd[InputDevice].timer_freq != 0) {
  3726. KillTimer(hDlg, in_wnd[InputDevice].id);
  3727. SetTimer(hDlg, in_wnd[InputDevice].id, in_wnd[InputDevice].timer_freq, NULL);
  3728. } else if (IsWindow(hDlg) && hDlg == wnd[1].hWnd && out_wnd[curouttab].timer_freq != 0) {
  3729. KillTimer(hDlg, out_wnd[curouttab].id);
  3730. SetTimer(hDlg, out_wnd[curouttab].id, out_wnd[curouttab].timer_freq, NULL);
  3731. }
  3732. }
  3733. break;
  3734. //Handle Minimize to systray here
  3735. case WM_SIZE:
  3736. {
  3737. switch (wParam) {
  3738. case SIZE_RESTORED:
  3739. {
  3740. RemoveSystrayIcon(hDlg, SYSTRAY_ICY_ICON);
  3741. ShowWindow(hDlg, SW_SHOW);
  3742. }
  3743. break;
  3744. case SIZE_MINIMIZED:
  3745. {
  3746. AddSystrayIcon(hDlg, SYSTRAY_ICY_ICON, GetICYIcon(),
  3747. SYSTRAY_MAXIMIZE_MSG, szDescription2W);
  3748. ShowWindow(hDlg, SW_HIDE);
  3749. }
  3750. break;
  3751. }
  3752. }
  3753. break;
  3754. case WM_COMMAND:
  3755. {
  3756. switch (LOWORD(wParam)) {
  3757. case IDC_NOTITLES:
  3758. case IDC_AUTOTITLE:
  3759. case IDC_MANUALTITLE:
  3760. //case IDC_EXTERNALTITLE:
  3761. {
  3762. // TODO will need to change around some of the logic to cope with the external option
  3763. if (HIWORD(wParam) == BN_CLICKED) {
  3764. MY_T_OUTPUT *Out = &Output[Connection_CurSelPos];
  3765. int lastAutoTitle = Out->AutoTitle;
  3766. Out->Config.doTitleUpdate = (LOWORD(wParam) != IDC_NOTITLES);
  3767. Out->AutoTitle = (LOWORD(wParam) == IDC_AUTOTITLE);
  3768. ini_modified = 1;
  3769. CheckRadioButton(hDlg, IDC_NOTITLES, IDC_MANUALTITLE, LOWORD(wParam));
  3770. UpdateTitleControls();
  3771. // if enabling then send the title update
  3772. if ((LOWORD(wParam) == IDC_AUTOTITLE) && lastAutoTitle != Out->AutoTitle) {
  3773. if (Out->Encoder != -1 && Out->Handle != -1) {
  3774. SHOUTCAST_OUTPUT *Enc = &Encoder[Out->Encoder];
  3775. if (WaitForSingleObject(Enc_mutex[Out->Encoder], INFINITE) == WAIT_OBJECT_0) {
  3776. std::vector<std::wstring> nextList;
  3777. nextList.clear();
  3778. Enc->UpdateTitle(0, nextList, Out->Handle, !!Out->NextTitles, true);
  3779. ReleaseMutex(Enc_mutex[Out->Encoder]);
  3780. }
  3781. }
  3782. }
  3783. }
  3784. }
  3785. break;
  3786. case IDC_SENDNEXTTITLES:
  3787. {
  3788. if (HIWORD(wParam) == BN_CLICKED) {
  3789. MY_T_OUTPUT *Out = &Output[Connection_CurSelPos];
  3790. Out->NextTitles = SendMessage((HWND) lParam, BM_GETCHECK, 0, 0) == BST_CHECKED;
  3791. ini_modified = 1;
  3792. }
  3793. }
  3794. break;
  3795. case IDC_VIEW_LOG:
  3796. {
  3797. wchar_t file[MAX_PATH];
  3798. ShellExecuteW(hMainDLG, L"open", GetSCLogFile(module.hwndParent, ARRAYSIZE(file), file, Connection_CurSelPos), 0, NULL, SW_SHOW);
  3799. }
  3800. break;
  3801. case IDC_CLEAR_LOG:
  3802. {
  3803. MY_T_OUTPUT *Out = &Output[Connection_CurSelPos];
  3804. if (Out->Logging && logFiles[Connection_CurSelPos] != INVALID_HANDLE_VALUE) {
  3805. SetFilePointer(logFiles[Connection_CurSelPos], 0, NULL, FILE_BEGIN);
  3806. SetEndOfFile(logFiles[Connection_CurSelPos]);
  3807. } else {
  3808. wchar_t file[MAX_PATH];
  3809. HANDLE handle = CreateFileW(GetSCLogFile(module.hwndParent, ARRAYSIZE(file), file, Connection_CurSelPos),
  3810. GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, 0, OPEN_EXISTING, 0, 0);
  3811. if (handle != INVALID_HANDLE_VALUE) {
  3812. SetFilePointer(handle, 0, NULL, FILE_BEGIN);
  3813. SetEndOfFile(handle);
  3814. CloseHandle(handle);
  3815. }
  3816. }
  3817. }
  3818. break;
  3819. case IDC_LOGGING:
  3820. {
  3821. if (HIWORD(wParam) == BN_CLICKED) {
  3822. MY_T_OUTPUT *Out = &Output[Connection_CurSelPos];
  3823. Out->Logging = SendMessage((HWND) lParam, BM_GETCHECK, 0, 0) == BST_CHECKED;
  3824. if (Out->Logging) {
  3825. StartLogging(Connection_CurSelPos,Out->LogCOS);
  3826. } else {
  3827. StopLogging(Connection_CurSelPos);
  3828. }
  3829. ini_modified = 1;
  3830. }
  3831. }
  3832. break;
  3833. case IDC_CLEAR_ON_STARTUP:
  3834. {
  3835. if (HIWORD(wParam) == BN_CLICKED) {
  3836. MY_T_OUTPUT *Out = &Output[Connection_CurSelPos];
  3837. Out->LogCOS = SendMessage((HWND) lParam, BM_GETCHECK, 0, 0) == BST_CHECKED;
  3838. ini_modified = 1;
  3839. }
  3840. }
  3841. break;
  3842. case IDC_NEXT_TRACK_LOG:
  3843. {
  3844. if (HIWORD(wParam) == BN_CLICKED) {
  3845. MY_T_OUTPUT *Out = &Output[Connection_CurSelPos];
  3846. Out->nextTrackLog = SendMessage((HWND) lParam, BM_GETCHECK, 0, 0) == BST_CHECKED;
  3847. if (Out->nextTrackLog) {
  3848. StartNextTracks(Connection_CurSelPos, Out->nextTrackPath);
  3849. FillNextTracks(Connection_CurSelPos, !!Out->nextTrackLogXML);
  3850. } else {
  3851. StopNextTracks(Connection_CurSelPos);
  3852. }
  3853. EnableWindowDlgItem(out_wnd[5].hWnd, IDC_NEXT_TRACK_XML, Out->nextTrackLog);
  3854. EnableWindowDlgItem(out_wnd[5].hWnd, IDC_NEXT_TRACK_EDIT, Out->nextTrackLog);
  3855. EnableWindowDlgItem(out_wnd[5].hWnd, IDC_NEXT_TRACK_BROWSE, Out->nextTrackLog);
  3856. ini_modified = 1;
  3857. }
  3858. }
  3859. break;
  3860. case IDC_NEXT_TRACK_XML:
  3861. {
  3862. if (HIWORD(wParam) == BN_CLICKED) {
  3863. MY_T_OUTPUT *Out = &Output[Connection_CurSelPos];
  3864. Out->nextTrackLogXML = SendMessage((HWND) lParam, BM_GETCHECK, 0, 0) == BST_CHECKED;
  3865. // reset the file if changing the state
  3866. if (Out->nextTrackLog) {
  3867. StopNextTracks(Connection_CurSelPos);
  3868. StartNextTracks(Connection_CurSelPos, Out->nextTrackPath);
  3869. FillNextTracks(Connection_CurSelPos, !!Out->nextTrackLogXML);
  3870. }
  3871. ini_modified = 1;
  3872. }
  3873. }
  3874. break;
  3875. case IDC_NEXT_TRACK_EDIT:
  3876. {
  3877. if (HIWORD(wParam) == EN_SETFOCUS) {
  3878. PostMessage((HWND)lParam, EM_SETSEL, 0, (LPARAM)-1);
  3879. }
  3880. }
  3881. break;
  3882. case IDC_NEXT_TRACK_BROWSE:
  3883. {
  3884. if (HIWORD(wParam) == BN_CLICKED) {
  3885. wchar_t filepath[MAX_PATH] = {0},
  3886. file[MAX_PATH] = {0},
  3887. filter[64] = {0};
  3888. // strip path so we can set initial directory, etc
  3889. MY_T_OUTPUT *Out = &Output[Connection_CurSelPos];
  3890. wcsncpy(filepath, Out->nextTrackPath, MAX_PATH);
  3891. wcsncpy(file, Out->nextTrackPath, MAX_PATH);
  3892. PathRemoveFileSpecW(filepath);
  3893. PathStripPathW(file);
  3894. OPENFILENAMEW ofn = {0};
  3895. ofn.lStructSize=sizeof(ofn);
  3896. ofn.hwndOwner=hMainDLG;
  3897. WASABI_API_LNGSTRINGW_BUF(IDS_ALL_FILES, filter, 64);
  3898. wchar_t * ptr=filter;
  3899. while(ptr && *ptr) {
  3900. if (*ptr==L'|') *ptr=0;
  3901. ptr++;
  3902. }
  3903. ofn.lpstrFilter=filter;
  3904. ofn.lpstrInitialDir=filepath;
  3905. ofn.lpstrFile=file;
  3906. ofn.nMaxFile=MAX_PATH;
  3907. ofn.Flags=OFN_HIDEREADONLY|OFN_PATHMUSTEXIST;
  3908. ofn.lpstrDefExt=L"log";
  3909. if (GetSaveFileNameW(&ofn))
  3910. {
  3911. // update things if the filename changed, etc
  3912. wcsncpy(Out->nextTrackPath, file, MAX_PATH);
  3913. SetDlgItemTextW(out_wnd[5].hWnd, IDC_NEXT_TRACK_EDIT, Out->nextTrackPath);
  3914. if (Out->nextTrackLog) {
  3915. StopNextTracks(Connection_CurSelPos);
  3916. StartNextTracks(Connection_CurSelPos, Out->nextTrackPath);
  3917. }
  3918. }
  3919. }
  3920. }
  3921. break;
  3922. case IDC_SAVE_ENCODED_AUDIO:
  3923. {
  3924. if (HIWORD(wParam) == BN_CLICKED) {
  3925. MY_T_OUTPUT *Out = &Output[Connection_CurSelPos];
  3926. Out->saveEncoded = SendMessage((HWND) lParam, BM_GETCHECK, 0, 0) == BST_CHECKED;
  3927. // reset the file if changing the state
  3928. if (Out->saveEncoded) {
  3929. StartSaveEncoded(Connection_CurSelPos, Out->saveEncodedPath);
  3930. } else {
  3931. StopSaveEncoded(Connection_CurSelPos);
  3932. }
  3933. ini_modified = 1;
  3934. }
  3935. }
  3936. break;
  3937. case IDC_SAVE_ENCODED_AUDIO_EDIT:
  3938. {
  3939. if (HIWORD(wParam) == EN_SETFOCUS) {
  3940. PostMessage((HWND)lParam, EM_SETSEL, 0, (LPARAM)-1);
  3941. }
  3942. }
  3943. break;
  3944. case IDC_SAVE_ENCODED_AUDIO_BROWSE:
  3945. {
  3946. if (HIWORD(wParam) == BN_CLICKED) {
  3947. wchar_t filepath[MAX_PATH] = {0},
  3948. file[MAX_PATH] = {0},
  3949. filter[64] = {0};
  3950. // strip path so we can set initial directory, etc
  3951. MY_T_OUTPUT *Out = &Output[Connection_CurSelPos];
  3952. wcsncpy(filepath, Out->saveEncodedPath, MAX_PATH);
  3953. wcsncpy(file, Out->saveEncodedPath, MAX_PATH);
  3954. PathRemoveFileSpecW(filepath);
  3955. PathStripPathW(file);
  3956. OPENFILENAMEW ofn = {0};
  3957. ofn.lStructSize=sizeof(ofn);
  3958. ofn.hwndOwner=hMainDLG;
  3959. // sets the default extension if not specified to the type of the encoder being used
  3960. ofn.lpstrDefExt=(Enc_LastType[Connection_CurSelPos] != 0 ?
  3961. (!strcmp(Encoder[Out->Encoder].GetEncoder()->GetContentType(),"audio/mpeg") ? L"mp3" :
  3962. (!strcmp(Encoder[Out->Encoder].GetEncoder()->GetContentType(),"audio/ogg") ? L"ogg" : L"aac")) : L"");
  3963. StringCchPrintfW(filter, ARRAYSIZE(filter), WASABI_API_LNGSTRINGW(IDS_MPEG_AUDIO_FILES), ofn.lpstrDefExt, ofn.lpstrDefExt);
  3964. wchar_t* ptr=filter;
  3965. while(ptr && *ptr) {
  3966. if (*ptr==L'|') *ptr=0;
  3967. ptr++;
  3968. }
  3969. ofn.lpstrFilter=filter;
  3970. ofn.lpstrInitialDir=filepath;
  3971. ofn.lpstrFile=file;
  3972. ofn.nMaxFile=MAX_PATH;
  3973. ofn.Flags=OFN_HIDEREADONLY|OFN_PATHMUSTEXIST;
  3974. if (GetSaveFileNameW(&ofn))
  3975. {
  3976. // update things if the filename changed, etc
  3977. wcsncpy(Out->saveEncodedPath, file, MAX_PATH);
  3978. SetDlgItemTextW(out_wnd[2].hWnd, IDC_SAVE_ENCODED_AUDIO_EDIT, Out->saveEncodedPath);
  3979. if (Out->saveEncoded) {
  3980. StopSaveEncoded(Connection_CurSelPos);
  3981. StartSaveEncoded(Connection_CurSelPos, Out->saveEncodedPath);
  3982. }
  3983. }
  3984. }
  3985. }
  3986. break;
  3987. case IDC_USE_ART:
  3988. {
  3989. if (HIWORD(wParam) == BN_CLICKED) {
  3990. MY_T_OUTPUT *Out = &Output[Connection_CurSelPos];
  3991. Out->useArt = SendMessage((HWND) lParam, BM_GETCHECK, 0, 0) == BST_CHECKED;
  3992. EnableWindowDlgItem(out_wnd[4].hWnd, IDC_USE_ART_PLAYING, Out->useArt);
  3993. EnableWindowDlgItem(out_wnd[4].hWnd, IDC_USE_ART_STREAM, Out->useArt);
  3994. EnableWindowDlgItem(out_wnd[4].hWnd, IDC_ART_EDIT, Out->useArt && Out->useStreamArt);
  3995. EnableWindowDlgItem(out_wnd[4].hWnd, IDC_ART_BROWSE, Out->useArt && Out->useStreamArt);
  3996. // only update if we need to do so
  3997. UpdateStreamAlbumArt(Out->Handle, Connection_CurSelPos, Out->stationArtPath, Out->useArt && Out->useStreamArt);
  3998. // this will update against what is read from the playing
  3999. UpdatePlayingAlbumArt(Out->Handle, Connection_CurSelPos, Out->useArt && Out->usePlayingArt);
  4000. Encoder[Connection_CurSelPos].UpdateArtwork(Out->Handle);
  4001. ini_modified = 1;
  4002. }
  4003. }
  4004. break;
  4005. case IDC_USE_ART_PLAYING:
  4006. {
  4007. if (HIWORD(wParam) == BN_CLICKED) {
  4008. MY_T_OUTPUT *Out = &Output[Connection_CurSelPos];
  4009. Out->usePlayingArt = SendMessage((HWND) lParam, BM_GETCHECK, 0, 0) == BST_CHECKED;
  4010. ini_modified = 1;
  4011. if(Out->usePlayingArt){
  4012. playingLength = 0;
  4013. playingType = 0x4101; // default in-case of issue
  4014. int w = 0, h = 0;
  4015. if (AGAVE_API_ALBUMART && AGAVE_API_ALBUMART->GetAlbumArt(lastFile, L"cover", &w, &h, &playingImage) == ALBUMART_SUCCESS) {
  4016. // make sure to free the original image after we've converted
  4017. ARGB32 *firstPlayingImage = playingImage;
  4018. playingImage = writeImg(playingImage, w, h, &playingLength, L"png");
  4019. WASABI_API_MEMMGR->sysFree(firstPlayingImage);
  4020. } else {
  4021. playingImage = 0;
  4022. }
  4023. }
  4024. UpdatePlayingAlbumArt(Out->Handle, Connection_CurSelPos, Out->useArt && Out->usePlayingArt);
  4025. Encoder[Connection_CurSelPos].UpdateArtwork(Out->Handle);
  4026. }
  4027. }
  4028. break;
  4029. case IDC_USE_ART_STREAM:
  4030. {
  4031. if (HIWORD(wParam) == BN_CLICKED) {
  4032. MY_T_OUTPUT *Out = &Output[Connection_CurSelPos];
  4033. Out->useStreamArt = SendMessage((HWND) lParam, BM_GETCHECK, 0, 0) == BST_CHECKED;
  4034. ini_modified = 1;
  4035. // skip this all if the mode is not enabled and only in SC2 mode
  4036. if ((LOBYTE(Out->Config.protocol) != 1) && Out->useArt) {
  4037. // this will only update generally on first connection
  4038. if (Out->useStreamArt && streamImage[Connection_CurSelPos] == (ARGB32 *)-1) {
  4039. UpdateStreamAlbumArt(Out->Handle, Connection_CurSelPos, Out->stationArtPath, !!Out->useStreamArt);
  4040. }
  4041. }
  4042. if (UpdateStreamAlbumArt(Out->Handle, Connection_CurSelPos, Out->stationArtPath, !!Out->useStreamArt)) {
  4043. Encoder[Connection_CurSelPos].UpdateArtwork(Out->Handle);
  4044. }
  4045. EnableWindowDlgItem(out_wnd[4].hWnd, IDC_ART_EDIT, Out->useStreamArt);
  4046. EnableWindowDlgItem(out_wnd[4].hWnd, IDC_ART_BROWSE, Out->useStreamArt);
  4047. }
  4048. }
  4049. break;
  4050. case IDC_ART_EDIT:
  4051. {
  4052. if (HIWORD(wParam) == EN_SETFOCUS) {
  4053. PostMessage((HWND)lParam, EM_SETSEL, 0, (LPARAM)-1);
  4054. }
  4055. }
  4056. break;
  4057. case IDC_ART_BROWSE:
  4058. {
  4059. if (HIWORD(wParam) == BN_CLICKED) {
  4060. wchar_t filepath[MAX_PATH] = {0},
  4061. file[MAX_PATH] = {0};
  4062. // strip path so we can set initial directory, etc
  4063. MY_T_OUTPUT *Out = &Output[Connection_CurSelPos];
  4064. wcsncpy(filepath, Out->stationArtPath, MAX_PATH);
  4065. wcsncpy(file, Out->stationArtPath, MAX_PATH);
  4066. PathRemoveFileSpecW(filepath);
  4067. PathStripPathW(file);
  4068. OPENFILENAMEW ofn = {0};
  4069. ofn.lStructSize=sizeof(ofn);
  4070. ofn.hwndOwner=hMainDLG;
  4071. ofn.lpstrInitialDir=filepath;
  4072. ofn.lpstrFile=file;
  4073. ofn.nMaxFile=MAX_PATH;
  4074. ofn.Flags=OFN_HIDEREADONLY|OFN_PATHMUSTEXIST;
  4075. ofn.lpstrDefExt=L"png";
  4076. ofn.nFilterIndex=lastFilterIndex;
  4077. static int tests_run = 0;
  4078. static wchar_t filter[1024] = {0}, *sff = filter;
  4079. if (!tests_run) {
  4080. tests_run = 1;
  4081. FOURCC imgload = svc_imageLoader::getServiceType();
  4082. int n = WASABI_API_SVC->service_getNumServices(imgload);
  4083. for (int i=0; i<n; i++) {
  4084. waServiceFactory *sf = WASABI_API_SVC->service_enumService(imgload, i);
  4085. if (sf) {
  4086. svc_imageLoader * l = (svc_imageLoader*)sf->getInterface();
  4087. if (l) {
  4088. static int tests_idx[4] = {0, 1, 2, 3};
  4089. size_t size = 1024;
  4090. int j = 0, tests_str[] = {IDS_JPEG_FILE, IDS_PNG_FILE, IDS_BMP_FILE, IDS_GIF_FILE};
  4091. wchar_t *tests[] = {L"*.jpg", L"*.png", L"*.bmp", L"*.gif"};
  4092. for (int i = 0; i < ARRAYSIZE(tests); i++) {
  4093. if (l->isMine(tests[i])) {
  4094. tests_idx[j] = i;
  4095. j++;
  4096. int len = 0;
  4097. LocalisedString(tests_str[i], sff, size);
  4098. size-=(len = wcslen(sff)+1);
  4099. sff+=len;
  4100. wcsncpy(sff, (!i ? L"*.jpg;*.jpeg" : tests[i]), size);
  4101. size-=(len = wcslen(sff)+1);
  4102. sff+=len;
  4103. }
  4104. }
  4105. sf->releaseInterface(l);
  4106. }
  4107. }
  4108. }
  4109. }
  4110. ofn.lpstrFilter = filter;
  4111. if (GetOpenFileNameW(&ofn))
  4112. {
  4113. // update things if the filename changed, etc
  4114. wcsncpy(Out->stationArtPath, file, MAX_PATH);
  4115. SetDlgItemTextW(out_wnd[4].hWnd, IDC_ART_EDIT, Out->stationArtPath);
  4116. if (UpdateStreamAlbumArt(Out->Handle, Connection_CurSelPos, Out->stationArtPath, !!Out->useStreamArt)) {
  4117. Encoder[Connection_CurSelPos].UpdateArtwork(Out->Handle);
  4118. }
  4119. }
  4120. lastFilterIndex = ofn.nFilterIndex;
  4121. }
  4122. }
  4123. break;
  4124. case IDC_AUTOCONNECT:
  4125. {
  4126. if (HIWORD(wParam) == BN_CLICKED) {
  4127. Output[Connection_CurSelPos].AutoConnect = SendMessage((HWND) lParam, BM_GETCHECK, 0, 0) == BST_CHECKED;
  4128. if (Output[Connection_CurSelPos].Encoder) {
  4129. if (WaitForSingleObject(Enc_mutex[Output[Connection_CurSelPos].Encoder], INFINITE) == WAIT_OBJECT_0) {
  4130. Encoder[Output[Connection_CurSelPos].Encoder].UpdateOutput(Output[Connection_CurSelPos].Handle);
  4131. ReleaseMutex(Enc_mutex[Output[Connection_CurSelPos].Encoder]);
  4132. }
  4133. }
  4134. }
  4135. }
  4136. break;
  4137. case IDC_RECONNECT:
  4138. {
  4139. if (HIWORD(wParam) == BN_CLICKED) {
  4140. Output[Connection_CurSelPos].Config.AutoRecon = SendMessage((HWND) lParam, BM_GETCHECK, 0, 0) == BST_CHECKED;
  4141. if (Output[Connection_CurSelPos].Encoder) {
  4142. if (WaitForSingleObject(Enc_mutex[Output[Connection_CurSelPos].Encoder], INFINITE) == WAIT_OBJECT_0) {
  4143. Encoder[Output[Connection_CurSelPos].Encoder].UpdateOutput(Output[Connection_CurSelPos].Handle);
  4144. ReleaseMutex(Enc_mutex[Output[Connection_CurSelPos].Encoder]);
  4145. }
  4146. }
  4147. }
  4148. }
  4149. break;
  4150. case IDC_PROTOCOL:
  4151. {
  4152. if (HIWORD(wParam) == CBN_SELCHANGE) {
  4153. MY_T_OUTPUT *Out = &Output[Connection_CurSelPos];
  4154. int cur_sel = SendMessage((HWND) lParam, CB_GETCURSEL, 0, 0),
  4155. protocol = SendMessage((HWND) lParam, CB_GETITEMDATA, cur_sel, 0);
  4156. Out->Config.protocol = MAKEWORD(protocol, !protocol);
  4157. // force a refresh on selection change
  4158. lastMode[Connection_CurSelPos] = -1;
  4159. // jkey: disable or enable userid stationid based on protocol.
  4160. if (Output[Connection_CurSelPos].Encoder) {
  4161. if (WaitForSingleObject(Enc_mutex[Output[Connection_CurSelPos].Encoder], INFINITE) == WAIT_OBJECT_0) {
  4162. Encoder[Output[Connection_CurSelPos].Encoder].UpdateOutput(Output[Connection_CurSelPos].Handle);
  4163. ReleaseMutex(Enc_mutex[Output[Connection_CurSelPos].Encoder]);
  4164. }
  4165. }
  4166. //shoutcast 2 else 1 enable aim,icq,irc
  4167. EnableWindowDlgItem(hDlg, IDC_STATIONID, (LOBYTE(Output[Connection_CurSelPos].Config.protocol) == 1));
  4168. UpdateTitleControls();
  4169. }
  4170. }
  4171. break;
  4172. case IDC_CONNECT:
  4173. {
  4174. if (HIWORD(wParam) == BN_CLICKED) {
  4175. MY_T_OUTPUT *Out = &Output[Connection_CurSelPos];
  4176. SHOUTCAST_OUTPUT *Enc = Out->Encoder != -1 ? &Encoder[Out->Encoder] : NULL;
  4177. if (Enc && Out->Handle != -1) {
  4178. int state = Enc->GetState(Out->Handle);
  4179. if (state == OUT_DISCONNECTED) { // disconnected... connect now
  4180. Enc->ConnectOutput(Out->Handle);
  4181. } else { // connected... disconnect now
  4182. Enc->DisconnectOutput(Out->Handle);
  4183. }
  4184. }
  4185. }
  4186. }
  4187. break;
  4188. case IDC_DEVBOX:
  4189. {
  4190. if (HIWORD(wParam) == CBN_SELCHANGE) {
  4191. Input_Device_ID = SendMessage((HWND) lParam, CB_GETCURSEL, 0, 0);
  4192. }
  4193. }
  4194. break;
  4195. case IDC_LOCK:
  4196. {
  4197. if (HIWORD(wParam) == BN_CLICKED) {
  4198. int checked = SendMessage((HWND) lParam, BM_GETCHECK, -1, -1) == BST_CHECKED;
  4199. EnableWindowDlgItem(hDlg, IDC_PTT, !checked);
  4200. SendDlgItemMessage(hDlg, IDC_PTT, BM_SETSTATE, checked ? BST_CHECKED : BST_UNCHECKED, 0);
  4201. KillTimer(hMainDLG, 2234);
  4202. KillTimer(hMainDLG, 2235);
  4203. if ((MicFadeStartTime != 0 || FadeStartTime != 0) && FadeOut != checked) {
  4204. clock_t myTime = clock();
  4205. if (FadeStartTime != 0) FadeStartTime = myTime - ((FadeTime * 100)-(myTime - FadeStartTime));
  4206. if (MicFadeStartTime != 0) MicFadeStartTime = myTime - ((MicFadeTime * 100)-(myTime - MicFadeStartTime));
  4207. }
  4208. if(!ptt_load && Restore_PTT || ptt_load) {
  4209. FadeOut = checked;
  4210. SetTimer(hMainDLG, 2234, 10, NULL); // fade out
  4211. SetTimer(hMainDLG, 2235, 10, NULL); // fade out
  4212. } else {
  4213. SetDeviceName();
  4214. }
  4215. ptt_load = 1;
  4216. //if (FadeOut) do_capture();
  4217. #ifdef CAPTURE_TESTING
  4218. if (FadeOut) {
  4219. if (!pPlayer) {
  4220. pPlayer = new Player(hMainDLG);
  4221. }
  4222. if (!pCallbacks) {
  4223. pCallbacks = new CPlayerCallbacks();
  4224. }
  4225. pPlayer->SetPlayerCallbacks(pCallbacks);
  4226. pPlayer->RefreshDeviceList(eRender);
  4227. pPlayer->RefreshDeviceList(eCapture);
  4228. pPlayer->SelectDefaultDevice(eRender, eConsole);
  4229. pPlayer->SelectDefaultDevice(eCapture, eConsole);
  4230. pPlayer->SelectDeviceFromList(eCapture, 0);
  4231. //pPlayer->SelectDeviceFromList(eRender, 2);
  4232. if (pPlayer->Play(eCaptureEndpoint) == FALSE) {
  4233. return TRUE;
  4234. }
  4235. }
  4236. #endif
  4237. }
  4238. }
  4239. break;
  4240. case IDC_LOCK_MODE:
  4241. {
  4242. HMENU hmenu = CreatePopupMenu();
  4243. RECT r;
  4244. GetWindowRect((HWND)lParam, &r);
  4245. MENUITEMINFOW i = {sizeof(i), MIIM_ID | MIIM_STATE | MIIM_TYPE, MFT_STRING,
  4246. Restore_PTT ? MFS_CHECKED : 0, 1337};
  4247. i.dwTypeData = LocalisedString(IDS_PTT_ON_STARTUP, NULL, 0);
  4248. InsertMenuItemW(hmenu, 0, TRUE, &i);
  4249. if (TrackPopupMenu(hmenu, TPM_LEFTALIGN | TPM_TOPALIGN | TPM_RETURNCMD, r.left, r.bottom, 0, (HWND)lParam, NULL) == 1337) {
  4250. Restore_PTT = !Restore_PTT;
  4251. }
  4252. DestroyMenu(hmenu);
  4253. }
  4254. break;
  4255. case IDC_REFRESH_DEVICES:
  4256. {
  4257. if (IsVistaUp()) {
  4258. SendDlgItemMessage(inWin,IDC_DEVBOX, CB_RESETCONTENT, 0, 0);
  4259. SetDeviceName();
  4260. }
  4261. }
  4262. break;
  4263. case IDC_MIXER:
  4264. {
  4265. if (HIWORD(wParam) == BN_CLICKED) {
  4266. // open vista / win7 or win2k / xp recording panel
  4267. // (more sensible esp. for vista / win7)
  4268. if (IsVistaUp()) {
  4269. ShellExecuteW(hMainDLG, L"open", L"control.exe", L"mmsys.cpl,,1", NULL, SW_SHOW);
  4270. } else {
  4271. ShellExecuteW(hMainDLG, L"open", L"sndvol32.exe", L"", NULL, SW_SHOW);
  4272. ShellExecuteW(hMainDLG, L"open", L"sndvol32.exe", L"/r", NULL, SW_SHOW);
  4273. }
  4274. }
  4275. }
  4276. break;
  4277. case IDC_OUTPUTLIST:
  4278. {
  4279. if (HIWORD(wParam) == LBN_SELCHANGE) {
  4280. Connection_CurSelPos = SendMessage((HWND) lParam, LB_GETCURSEL, 0, 0);
  4281. // force a refresh on selection change
  4282. lastMode[Connection_CurSelPos] = -1;
  4283. // do checks to see if we need to update the error state of the tab items
  4284. if (IsWindow(outTabWnd)) {
  4285. RECT r = {0};
  4286. for (int i = 0; i < MAX_OUTWNDS; i++) {
  4287. TabCtrl_GetItemRect(outTabWnd, i, &r);
  4288. InvalidateRect(outTabWnd, &r, 0);
  4289. }
  4290. TabCtrl_GetItemRect(GetDlgItem(hMainDLG, IDC_TAB), 1, &r);
  4291. InvalidateRect(GetDlgItem(hMainDLG, IDC_TAB), &r, 0);
  4292. }
  4293. T_OUTPUT_CONFIG *Out = &Output[Connection_CurSelPos].Config;
  4294. MY_T_OUTPUT * OutEnc = &Output[Connection_CurSelPos];
  4295. int sc2mode = (LOBYTE(Out->protocol) != 1);
  4296. // Output page 1
  4297. SendDlgItemMessage(out_wnd[0].hWnd, IDC_ADDRESS, EM_SETLIMITTEXT, ARRAYSIZE(Out->Address) - 1, 0);
  4298. SetDlgItemText(out_wnd[0].hWnd, IDC_ADDRESS, Out->Address);
  4299. SendDlgItemMessage(out_wnd[0].hWnd, IDC_STATIONID, EM_SETLIMITTEXT, 10, 0);
  4300. SetDlgItemText(out_wnd[0].hWnd, IDC_STATIONID, Out->StationID);
  4301. SendDlgItemMessage(out_wnd[0].hWnd, IDC_USERID, EM_SETLIMITTEXT, ARRAYSIZE(Out->UserID) - 1, 0);
  4302. SetDlgItemText(out_wnd[0].hWnd, IDC_USERID, Out->UserID);
  4303. SetDlgItemInt(out_wnd[0].hWnd, IDC_PORT, Out->Port, 0);
  4304. SendDlgItemMessage(out_wnd[0].hWnd, IDC_PASSWORD, EM_SETLIMITTEXT, ARRAYSIZE(Out->Password) - 1, 0);
  4305. SetDlgItemText(out_wnd[0].hWnd, IDC_PASSWORD, Out->Password);
  4306. int encval = OutEnc->Encoder;
  4307. SendDlgItemMessage(out_wnd[0].hWnd, IDC_RECONNECT, BM_SETCHECK, Out->AutoRecon ? BST_CHECKED : BST_UNCHECKED, 0);
  4308. SendDlgItemMessage(wnd[1].hWnd, IDC_AUTOCONNECT, BM_SETCHECK, OutEnc->AutoConnect ? BST_CHECKED : BST_UNCHECKED, 0);
  4309. SetDlgItemInt(out_wnd[0].hWnd, IDC_TIMEOUT, Out->ReconTime, 0);
  4310. EnableWindowDlgItem(out_wnd[0].hWnd, IDC_STATIONID, sc2mode);
  4311. SendDlgItemMessage(out_wnd[0].hWnd, IDC_PROTOCOL, CB_SETCURSEL, (HIBYTE(Out->protocol) ? 0 : (sc2mode ? 1 : 2)), 0);
  4312. // Output page 2
  4313. SendDlgItemMessage(out_wnd[1].hWnd, IDC_PUBLIC, BM_SETCHECK, Out->Public ? BST_CHECKED : BST_UNCHECKED, 0);
  4314. SendDlgItemMessage(out_wnd[1].hWnd, IDC_DESCRIPTION, EM_SETLIMITTEXT, ARRAYSIZE(Out->Description) - 1, 0);
  4315. SetDlgItemText(out_wnd[1].hWnd, IDC_DESCRIPTION, Out->Description);
  4316. SendDlgItemMessage(out_wnd[1].hWnd, IDC_SERVERURL, EM_SETLIMITTEXT, ARRAYSIZE(Out->ServerURL) - 1, 0);
  4317. SetDlgItemText(out_wnd[1].hWnd, IDC_SERVERURL, Out->ServerURL);
  4318. SendDlgItemMessage(out_wnd[1].hWnd, IDC_GENRE, EM_SETLIMITTEXT, ARRAYSIZE(Out->Genre) - 1, 0);
  4319. SetDlgItemText(out_wnd[1].hWnd, IDC_GENRE, Out->Genre);
  4320. SendDlgItemMessage(out_wnd[1].hWnd, IDC_AIM, EM_SETLIMITTEXT, ARRAYSIZE(Out->AIM) - 1, 0);
  4321. SetDlgItemText(out_wnd[1].hWnd, IDC_AIM, Out->AIM);
  4322. SendDlgItemMessage(out_wnd[1].hWnd, IDC_ICQ, EM_SETLIMITTEXT, ARRAYSIZE(Out->ICQ) - 1, 0);
  4323. SetDlgItemText(out_wnd[1].hWnd, IDC_ICQ, Out->ICQ);
  4324. SendDlgItemMessage(out_wnd[1].hWnd, IDC_IRC, EM_SETLIMITTEXT, ARRAYSIZE(Out->IRC) - 1, 0);
  4325. SetDlgItemText(out_wnd[1].hWnd, IDC_IRC, Out->IRC);
  4326. SendDlgItemMessage(out_wnd[1].hWnd, IDC_AUTOCONNECT, BM_SETCHECK, OutEnc->AutoConnect ? BST_CHECKED : BST_UNCHECKED, 0);
  4327. // setup the handling of the encoder saving options
  4328. SendDlgItemMessage(out_wnd[2].hWnd, IDC_SAVE_ENCODED_AUDIO_EDIT, EM_SETLIMITTEXT, ARRAYSIZE(OutEnc->stationArtPath) - 1, 0);
  4329. SetDlgItemTextW(out_wnd[2].hWnd, IDC_SAVE_ENCODED_AUDIO_EDIT, OutEnc->saveEncodedPath);
  4330. SendDlgItemMessage(out_wnd[2].hWnd, IDC_SAVE_ENCODED_AUDIO, BM_SETCHECK, OutEnc->saveEncoded ? BST_CHECKED : BST_UNCHECKED, 0);
  4331. // setup the handling of the titles options
  4332. SendDlgItemMessage(out_wnd[3].hWnd, IDC_TITLE, EM_SETLIMITTEXT, ARRAYSIZE(Out->Now) - 1, 0);
  4333. SetDlgItemText(out_wnd[3].hWnd, IDC_TITLE, Out->Now);
  4334. SendDlgItemMessage(out_wnd[3].hWnd, IDC_NEXT, EM_SETLIMITTEXT, ARRAYSIZE(Out->Next) - 1, 0);
  4335. SetDlgItemText(out_wnd[3].hWnd, IDC_NEXT, Out->Next);
  4336. CheckRadioButton(out_wnd[3].hWnd, IDC_NOTITLES, IDC_MANUALTITLE, (Out->doTitleUpdate ? (OutEnc->AutoTitle ? IDC_AUTOTITLE : IDC_MANUALTITLE) : IDC_NOTITLES));
  4337. SendDlgItemMessage(out_wnd[3].hWnd, IDC_SENDNEXTTITLES, BM_SETCHECK, OutEnc->NextTitles ? BST_CHECKED : BST_UNCHECKED, 0);
  4338. UpdateTitleControls();
  4339. // setup the handling of the artwork options
  4340. SendDlgItemMessage(out_wnd[4].hWnd, IDC_ART_EDIT, EM_SETLIMITTEXT, ARRAYSIZE(OutEnc->stationArtPath) - 1, 0);
  4341. SetDlgItemTextW(out_wnd[4].hWnd, IDC_ART_EDIT, OutEnc->stationArtPath);
  4342. SendDlgItemMessage(out_wnd[4].hWnd, IDC_USE_ART, BM_SETCHECK, OutEnc->useArt ? BST_CHECKED : BST_UNCHECKED, 0);
  4343. SendDlgItemMessage(out_wnd[4].hWnd, IDC_USE_ART_PLAYING, BM_SETCHECK, OutEnc->usePlayingArt ? BST_CHECKED : BST_UNCHECKED, 0);
  4344. SendDlgItemMessage(out_wnd[4].hWnd, IDC_USE_ART_STREAM, BM_SETCHECK, OutEnc->useStreamArt ? BST_CHECKED : BST_UNCHECKED, 0);
  4345. EnableWindowDlgItem(out_wnd[4].hWnd, IDC_USE_ART_PLAYING, OutEnc->useArt);
  4346. EnableWindowDlgItem(out_wnd[4].hWnd, IDC_USE_ART_STREAM, OutEnc->useArt);
  4347. EnableWindowDlgItem(out_wnd[4].hWnd, IDC_ART_EDIT, OutEnc->useArt && OutEnc->useStreamArt);
  4348. EnableWindowDlgItem(out_wnd[4].hWnd, IDC_ART_BROWSE, OutEnc->useArt && OutEnc->useStreamArt);
  4349. UpdateArtworkMessage();
  4350. // setup the handling of the next track logging option
  4351. SendDlgItemMessage(out_wnd[5].hWnd, IDC_LOGGING, BM_SETCHECK, OutEnc->Logging ? BST_CHECKED : BST_UNCHECKED, 0);
  4352. SendDlgItemMessage(out_wnd[5].hWnd, IDC_CLEAR_ON_STARTUP, BM_SETCHECK, OutEnc->LogCOS ? BST_CHECKED : BST_UNCHECKED, 0);
  4353. SendDlgItemMessage(out_wnd[5].hWnd, IDC_NEXT_TRACK_LOG, BM_SETCHECK, OutEnc->nextTrackLog ? BST_CHECKED : BST_UNCHECKED, 0);
  4354. SendDlgItemMessage(out_wnd[5].hWnd, IDC_NEXT_TRACK_XML, BM_SETCHECK, OutEnc->nextTrackLogXML ? BST_CHECKED : BST_UNCHECKED, 0);
  4355. SendDlgItemMessage(out_wnd[5].hWnd, IDC_NEXT_TRACK_EDIT, EM_SETLIMITTEXT, ARRAYSIZE(OutEnc->nextTrackPath) - 1, 0);
  4356. SetDlgItemTextW(out_wnd[5].hWnd, IDC_NEXT_TRACK_EDIT, OutEnc->nextTrackPath);
  4357. EnableWindowDlgItem(out_wnd[5].hWnd, IDC_NEXT_TRACK_XML, OutEnc->nextTrackLog);
  4358. EnableWindowDlgItem(out_wnd[5].hWnd, IDC_NEXT_TRACK_EDIT, OutEnc->nextTrackLog);
  4359. EnableWindowDlgItem(out_wnd[5].hWnd, IDC_NEXT_TRACK_BROWSE, OutEnc->nextTrackLog);
  4360. // this is sent to the encoders tab so it will update the selection for the current instance
  4361. // note: this is a change in build 009 to remove the prior listbox and reduce ui inconsistency
  4362. SendMessage(out_wnd[2].hWnd, WM_COMMAND, MAKEWPARAM(IDC_ENCODERLIST, LBN_SELCHANGE), (LPARAM) GetDlgItem(wnd[2].hWnd, IDC_ENCODERLIST));
  4363. ini_modified = 1;
  4364. }
  4365. }
  4366. break;
  4367. case IDC_INPUTSETUP:
  4368. {
  4369. if (HIWORD(wParam) == CBN_SELCHANGE) {
  4370. if (WaitForSingleObject(cf_mutex, INFINITE) == WAIT_OBJECT_0) {
  4371. Crossfader->SetChannels(LineInputAttribs[(InputDevice == 0 ? 3 : Input_CurSelPos)].nch);
  4372. Crossfader->SetSampleRate(LineInputAttribs[(InputDevice == 0 ? 3 : Input_CurSelPos)].srate);
  4373. ReleaseMutex(cf_mutex);
  4374. }
  4375. int attrib = SendMessage((HWND) lParam, CB_GETCURSEL, 0, 0);
  4376. if (attrib != Input_CurSelPos) {
  4377. SuspendThread(hthread);
  4378. Soundcard.Close();
  4379. if (InputDevice == 1) {
  4380. Input_CurSelPos = attrib;
  4381. }
  4382. for (int i = 0; i < NUM_ENCODERS; i++) {
  4383. if (WaitForSingleObject(Enc_mutex[i], INFINITE) == WAIT_OBJECT_0) {
  4384. C_ENCODER *Enc = Encoder[i].GetEncoder();
  4385. if (Enc) {
  4386. int infosize = sizeof (T_EncoderIOVals);
  4387. T_EncoderIOVals *encset = (T_EncoderIOVals *) Enc->GetExtInfo(&infosize);
  4388. if (encset && infosize) {
  4389. T_EncoderIOVals *EncSettings = (T_EncoderIOVals *) malloc(infosize);
  4390. memcpy(EncSettings, encset, infosize);
  4391. if (strcmp(Enc->GetName(), "MP3 Encoder") == 0) {
  4392. ((T_ENCODER_MP3_INFO *) EncSettings)->input_numChannels = (InputDevice == 0 ? InputConfig.nch : LineInputAttribs[Input_CurSelPos].nch);
  4393. ((T_ENCODER_MP3_INFO *) EncSettings)->input_sampleRate = (InputDevice == 0 ? InputConfig.srate : LineInputAttribs[Input_CurSelPos].srate);
  4394. } else if (strcmp(Enc->GetName(), "Fraunhofer Encoder") == 0) {
  4395. ((T_ENCODER_FHGAAC_INFO *) EncSettings)->input_numChannels = (InputDevice == 0 ? InputConfig.nch : LineInputAttribs[Input_CurSelPos].nch);
  4396. ((T_ENCODER_FHGAAC_INFO *) EncSettings)->input_sampleRate = (InputDevice == 0 ? InputConfig.srate : LineInputAttribs[Input_CurSelPos].srate);
  4397. } else if (strcmp(Enc->GetName(), "AAC+ Encoder") == 0) {
  4398. ((T_ENCODER_AACP_INFO *) EncSettings)->input_numChannels = (InputDevice == 0 ? InputConfig.nch : LineInputAttribs[Input_CurSelPos].nch);
  4399. ((T_ENCODER_AACP_INFO *) EncSettings)->input_sampleRate = (InputDevice == 0 ? InputConfig.srate : LineInputAttribs[Input_CurSelPos].srate);
  4400. }
  4401. #ifdef USE_OGG
  4402. else if (strcmp(Enc->GetName(), "OGG Vorbis Encoder") == 0) {
  4403. ((T_ENCODER_OGG_INFO *) EncSettings)->input_numChannels = (InputDevice == 0 ? InputConfig.nch : LineInputAttribs[Input_CurSelPos].nch);
  4404. ((T_ENCODER_OGG_INFO *) EncSettings)->input_sampleRate = (InputDevice == 0 ? InputConfig.srate : LineInputAttribs[Input_CurSelPos].srate);
  4405. }
  4406. #endif // USE_OGG
  4407. Enc->ChangeSettings(EncSettings);
  4408. free(EncSettings);
  4409. }
  4410. }
  4411. ReleaseMutex(Enc_mutex[i]);
  4412. }
  4413. }
  4414. Soundcard.Create((InputDevice == 0 ? InputConfig.srate : LineInputAttribs[Input_CurSelPos].srate), (InputDevice == 0 ? InputConfig.nch : LineInputAttribs[Input_CurSelPos].nch));
  4415. ResumeThread(hthread);
  4416. ini_modified = 1;
  4417. }
  4418. }
  4419. }
  4420. break;
  4421. case IDC_INPUT_WINAMP:
  4422. case IDC_INPUT_SOUNDCARD:
  4423. {
  4424. // update the input mode from the summary page options
  4425. HWND inputCtrl = GetDlgItem(wnd[2].hWnd, IDC_INPUTDEVICE);
  4426. SendMessage(inputCtrl, CB_SETCURSEL, (LOWORD(wParam) - IDC_INPUT_WINAMP), 0);
  4427. SendMessage(wnd[2].hWnd, WM_COMMAND, MAKEWPARAM(IDC_INPUTDEVICE,CBN_SELCHANGE), (LPARAM)inputCtrl);
  4428. }
  4429. break;
  4430. case IDC_INPUTDEVICE:
  4431. {
  4432. if (HIWORD(wParam) == CBN_SELCHANGE) {
  4433. int this_device = SendMessage((HWND) lParam, CB_GETCURSEL, 0, 0);
  4434. if (InputDevice != this_device) {
  4435. SuspendThread(hthread);
  4436. Soundcard.Close();
  4437. InputDevice = this_device;
  4438. if (InputDevice == 0) { // winamp
  4439. SendMessage(in_wnd[this_device].hWnd, WM_HSCROLL, 0, (LPARAM) GetDlgItem(in_wnd[this_device].hWnd, IDC_MUSSLIDER));
  4440. SendMessage(in_wnd[this_device].hWnd, WM_HSCROLL, 0, (LPARAM) GetDlgItem(in_wnd[this_device].hWnd, IDC_MUS2SLIDER));
  4441. SendMessage(in_wnd[this_device].hWnd, WM_HSCROLL, 0, (LPARAM) GetDlgItem(in_wnd[this_device].hWnd, IDC_MICSLIDER));
  4442. SendMessage(in_wnd[this_device].hWnd, WM_HSCROLL, 0, (LPARAM) GetDlgItem(in_wnd[this_device].hWnd, IDC_FADESLIDER));
  4443. SendMessage(in_wnd[this_device].hWnd, WM_HSCROLL, 0, (LPARAM) GetDlgItem(in_wnd[this_device].hWnd, IDC_MICFADESLIDER));
  4444. }
  4445. for (int i = 0; i < NUM_ENCODERS; i++) {
  4446. if (WaitForSingleObject(Enc_mutex[i], INFINITE) == WAIT_OBJECT_0) {
  4447. C_ENCODER *Enc = Encoder[i].GetEncoder();
  4448. if (Enc) {
  4449. int infosize = sizeof (T_EncoderIOVals);
  4450. T_EncoderIOVals *encset = (T_EncoderIOVals *) Enc->GetExtInfo(&infosize);
  4451. if (encset && infosize) {
  4452. T_EncoderIOVals *EncSettings = (T_EncoderIOVals *) malloc(infosize);
  4453. memcpy(EncSettings, encset, infosize);
  4454. if (strcmp(Enc->GetName(), "MP3 Encoder") == 0) {
  4455. ((T_ENCODER_MP3_INFO *) EncSettings)->input_numChannels = (InputDevice == 0 ? InputConfig.nch : LineInputAttribs[Input_CurSelPos].nch);
  4456. ((T_ENCODER_MP3_INFO *) EncSettings)->input_sampleRate = (InputDevice == 0 ? InputConfig.srate : LineInputAttribs[Input_CurSelPos].srate);
  4457. } else if (strcmp(Enc->GetName(), "Fraunhofer Encoder") == 0) {
  4458. ((T_ENCODER_FHGAAC_INFO *) EncSettings)->input_numChannels = (InputDevice == 0 ? InputConfig.nch : LineInputAttribs[Input_CurSelPos].nch);
  4459. ((T_ENCODER_FHGAAC_INFO *) EncSettings)->input_sampleRate = (InputDevice == 0 ? InputConfig.srate : LineInputAttribs[Input_CurSelPos].srate);
  4460. } else if (strcmp(Enc->GetName(), "AAC+ Encoder") == 0) {
  4461. ((T_ENCODER_AACP_INFO *) EncSettings)->input_numChannels = (InputDevice == 0 ? InputConfig.nch : LineInputAttribs[Input_CurSelPos].nch);
  4462. ((T_ENCODER_AACP_INFO *) EncSettings)->input_sampleRate = (InputDevice == 0 ? InputConfig.srate : LineInputAttribs[Input_CurSelPos].srate);
  4463. }
  4464. #ifdef USE_OGG
  4465. else if (strcmp(Enc->GetName(), "OGG Vorbis Encoder") == 0) {
  4466. ((T_ENCODER_OGG_INFO *) EncSettings)->input_numChannels = (InputDevice == 0 ? InputConfig.nch : LineInputAttribs[Input_CurSelPos].nch);
  4467. ((T_ENCODER_OGG_INFO *) EncSettings)->input_sampleRate = (InputDevice == 0 ? InputConfig.srate : LineInputAttribs[Input_CurSelPos].srate);
  4468. }
  4469. #endif // USE_OGG
  4470. Enc->ChangeSettings(EncSettings);
  4471. free(EncSettings);
  4472. }
  4473. }
  4474. ReleaseMutex(Enc_mutex[i]);
  4475. }
  4476. }
  4477. Soundcard.Create((InputDevice == 0 ? InputConfig.srate : LineInputAttribs[Input_CurSelPos].srate), (InputDevice == 0 ? InputConfig.nch : LineInputAttribs[Input_CurSelPos].nch));
  4478. DisplayDeviceName();
  4479. CheckRadioButton(wnd[0].hWnd, IDC_INPUT_WINAMP, IDC_INPUT_SOUNDCARD, (IDC_INPUT_WINAMP + InputDevice));
  4480. peak_vu_l = peak_vu_r = -90;
  4481. ResumeThread(hthread);
  4482. ini_modified = 1;
  4483. }
  4484. SendDlgItemMessage(hDlg, IDC_INPUTSETUP, CB_RESETCONTENT, 0, 0);
  4485. if (InputDevice == 1) {
  4486. wchar_t temp[128];
  4487. int num_input_items = ARRAYSIZE(LineInputAttribs);
  4488. for (int i = 0; i < num_input_items; i++) {
  4489. wchar_t tmp[32];
  4490. StringCchPrintfW(temp, ARRAYSIZE(temp), LocalisedString(IDS_X_HZ_X, tmp, 32), LineInputAttribs[i].srate, LocalisedString(LineInputAttribs[i].nch == 1 ? IDS_MONO : IDS_STEREO, NULL, 0));
  4491. SendDlgItemMessageW(hDlg, IDC_INPUTSETUP, CB_ADDSTRING, 0, (LPARAM) temp);
  4492. }
  4493. SendDlgItemMessage(hDlg, IDC_INPUTSETUP, CB_SETCURSEL, Input_CurSelPos, 0);
  4494. }
  4495. for (int i = 0; i < num_inwnds; i++) ShowWindow(in_wnd[i].hWnd, i == InputDevice && curtab == 2 ? SW_SHOW : SW_HIDE);
  4496. SendMessage(hDlg, WM_COMMAND, MAKEWPARAM(IDC_INPUTSETUP, CBN_SELCHANGE), (LPARAM) GetDlgItem(hDlg, IDC_INPUTSETUP));
  4497. ShowWindowDlgItem(hDlg, IDC_INPUTSETUPSTATIC, InputDevice == 1);
  4498. ShowWindowDlgItem(hDlg, IDC_INPUTSETUP, InputDevice == 1);
  4499. }
  4500. }
  4501. break;
  4502. // server box
  4503. case IDC_ADDRESS:
  4504. {
  4505. if (HIWORD(wParam) == EN_UPDATE) {
  4506. T_OUTPUT_CONFIG *Out = &Output[Connection_CurSelPos].Config;
  4507. GetWindowText((HWND) lParam, Out->Address, ARRAYSIZE(Out->Address));
  4508. ini_modified = 1;
  4509. } else if (HIWORD(wParam) == EN_SETFOCUS) {
  4510. PostMessage((HWND)lParam, EM_SETSEL, 0, (LPARAM)-1);
  4511. }
  4512. }
  4513. break;
  4514. // stream ID box
  4515. case IDC_STATIONID:
  4516. {
  4517. if (HIWORD(wParam) == EN_UPDATE) {
  4518. BOOL success = FALSE;
  4519. int value = GetDlgItemInt(hDlg, LOWORD(wParam), &success, TRUE);
  4520. T_OUTPUT_CONFIG *Out = &Output[Connection_CurSelPos].Config;
  4521. GetWindowText((HWND) lParam, Out->StationID, ARRAYSIZE(Out->StationID));
  4522. // check and set the default as required
  4523. if (!Out->StationID[0] || (success && value < 1 || !success && value == 0)) {
  4524. SetWindowTextW((HWND) lParam, L"1");
  4525. lstrcpyn(Out->StationID, "1", ARRAYSIZE(Out->StationID));
  4526. } else if (Out->StationID[0] && (success && value > 2147483647)) {
  4527. SetWindowTextW((HWND) lParam, L"2147483647");
  4528. lstrcpyn(Out->StationID, "2147483647", ARRAYSIZE(Out->StationID));
  4529. }
  4530. ini_modified = 1;
  4531. } else if (HIWORD(wParam) == EN_SETFOCUS) {
  4532. PostMessage((HWND)lParam, EM_SETSEL, 0, (LPARAM)-1);
  4533. }
  4534. }
  4535. break;
  4536. case IDC_USERID:
  4537. {
  4538. if (HIWORD(wParam) == EN_UPDATE) {
  4539. T_OUTPUT_CONFIG *Out = &Output[Connection_CurSelPos].Config;
  4540. GetWindowText((HWND) lParam, Out->UserID, ARRAYSIZE(Out->UserID));
  4541. ini_modified = 1;
  4542. } else if (HIWORD(wParam) == EN_SETFOCUS) {
  4543. PostMessage((HWND)lParam, EM_SETSEL, 0, (LPARAM)-1);
  4544. }
  4545. }
  4546. break;
  4547. // server port
  4548. case IDC_PORT:
  4549. {
  4550. if (HIWORD(wParam) == EN_UPDATE) {
  4551. BOOL success = FALSE;
  4552. int value = GetDlgItemInt(hDlg, LOWORD(wParam), &success, TRUE);
  4553. T_OUTPUT_CONFIG *Out = &Output[Connection_CurSelPos].Config;
  4554. // check and set the default as required
  4555. if ((success && value < 1 || !success && value == 0)) {
  4556. SetWindowTextW((HWND) lParam, L"8000");
  4557. Out->Port = 8000;
  4558. } else if ((success && value > 65535)) {
  4559. SetWindowTextW((HWND) lParam, L"65535");
  4560. Out->Port = 65535;
  4561. } else {
  4562. Out->Port = value;
  4563. }
  4564. ini_modified = 1;
  4565. } else if (HIWORD(wParam) == EN_SETFOCUS) {
  4566. PostMessage((HWND)lParam, EM_SETSEL, 0, (LPARAM)-1);
  4567. }
  4568. }
  4569. break;
  4570. // password
  4571. case IDC_PASSWORD:
  4572. {
  4573. if (HIWORD(wParam) == EN_UPDATE) {
  4574. T_OUTPUT_CONFIG *Out = &Output[Connection_CurSelPos].Config;
  4575. GetWindowText((HWND) lParam, Out->Password, ARRAYSIZE(Out->Password));
  4576. ini_modified = 1;
  4577. } else if (HIWORD(wParam) == EN_SETFOCUS) {
  4578. PostMessage((HWND)lParam, EM_SETSEL, 0, (LPARAM)-1);
  4579. }
  4580. }
  4581. break;
  4582. case IDC_SEND:
  4583. {
  4584. EnableWindowDlgItem(hDlg, IDC_SEND, FALSE);
  4585. MY_T_OUTPUT *Out = &Output[Connection_CurSelPos];
  4586. if (Out->Encoder != -1 && Out->Handle != -1) {
  4587. wchar_t title[1024] = {0}, next[1024] = {0};
  4588. SHOUTCAST_OUTPUT *Enc = &Encoder[Out->Encoder];
  4589. GetWindowTextW(GetDlgItem(out_wnd[3].hWnd, IDC_TITLE), title, ARRAYSIZE(title));
  4590. GetWindowTextW(GetDlgItem(out_wnd[3].hWnd, IDC_NEXT), next, ARRAYSIZE(next));
  4591. ini_modified = 1;
  4592. if (WaitForSingleObject(Enc_mutex[Out->Encoder], INFINITE) == WAIT_OBJECT_0) {
  4593. std::vector<std::wstring> nextList;
  4594. std::vector<int> nextListIdx;
  4595. nextList.clear();
  4596. nextListIdx.clear();
  4597. if (((Out->AutoTitle == 1 && Out->NextTitles) || Out->AutoTitle == 0) && next[0]) {
  4598. nextList.push_back(next);
  4599. nextListIdx.push_back(-1);
  4600. }
  4601. if (Out->nextTrackLog) {
  4602. WriteNextTracks(Connection_CurSelPos, module.hwndParent, nextListIdx, nextList, !!Out->nextTrackLogXML);
  4603. }
  4604. // check if in v2 mode and have a next title specified so as to change the send flag
  4605. Enc->UpdateTitle(title, nextList, Out->Handle, !!nextList.size(), false);
  4606. ReleaseMutex(Enc_mutex[Out->Encoder]);
  4607. }
  4608. }
  4609. }
  4610. break;
  4611. case IDC_TITLE:
  4612. {
  4613. if (HIWORD(wParam) == EN_UPDATE) {
  4614. int length = GetWindowTextLength((HWND)lParam);
  4615. EnableWindowDlgItem(out_wnd[3].hWnd, IDC_SEND, (length > 0));
  4616. MY_T_OUTPUT *Out = &Output[Connection_CurSelPos];
  4617. EnableWindowDlgItem(out_wnd[3].hWnd, IDC_NEXT,
  4618. (length > 0 && (LOBYTE(Out->Config.protocol) != 1)));
  4619. char temp[sizeof(Out->Config.Now)];
  4620. GetWindowText((HWND) lParam, temp, ARRAYSIZE(temp));
  4621. if (strcmp(temp, Out->Config.Now) != 0) {
  4622. lstrcpyn(Out->Config.Now, temp, ARRAYSIZE(Out->Config.Now));
  4623. ini_modified = 1;
  4624. }
  4625. }
  4626. }
  4627. break;
  4628. case IDC_NEXT:
  4629. {
  4630. if (HIWORD(wParam) == EN_UPDATE) {
  4631. EnableWindowDlgItem(out_wnd[3].hWnd, IDC_SEND, TRUE);
  4632. MY_T_OUTPUT *Out = &Output[Connection_CurSelPos];
  4633. char temp[sizeof(Out->Config.Next)];
  4634. GetWindowText((HWND) lParam, temp, ARRAYSIZE(temp));
  4635. if (strcmp(temp, Out->Config.Next) != 0) {
  4636. lstrcpyn(Out->Config.Next, temp, ARRAYSIZE(Out->Config.Next));
  4637. ini_modified = 1;
  4638. }
  4639. }
  4640. }
  4641. break;
  4642. case IDC_TIMEOUT:
  4643. {
  4644. if (HIWORD(wParam) == EN_UPDATE) {
  4645. MY_T_OUTPUT *Out = &Output[Connection_CurSelPos];
  4646. char temp[128] = {0};
  4647. GetWindowText((HWND) lParam, temp, ARRAYSIZE(temp));
  4648. int rt = atoi(temp);
  4649. if (rt < 1) {
  4650. rt = 5;
  4651. SetDlgItemInt(out_wnd[0].hWnd, IDC_TIMEOUT, 5, 0);
  4652. }
  4653. if (Out->Config.ReconTime != rt) {
  4654. Out->Config.ReconTime = rt;
  4655. if (Out->Encoder) {
  4656. if (WaitForSingleObject(Enc_mutex[Out->Encoder], INFINITE) == WAIT_OBJECT_0) {
  4657. Encoder[Out->Encoder].UpdateOutput(Out->Handle);
  4658. ReleaseMutex(Enc_mutex[Out->Encoder]);
  4659. }
  4660. }
  4661. ini_modified = 1;
  4662. }
  4663. } else if (HIWORD(wParam) == EN_SETFOCUS) {
  4664. PostMessage((HWND)lParam, EM_SETSEL, 0, (LPARAM)-1);
  4665. }
  4666. }
  4667. break;
  4668. // these will reconnect the Output on edit
  4669. case IDC_PUBLIC:
  4670. {
  4671. if (HIWORD(wParam) == BN_CLICKED) {
  4672. MY_T_OUTPUT *Out = &Output[Connection_CurSelPos];
  4673. Out->Config.Public = SendMessage((HWND) lParam, BM_GETCHECK, 0, 0) == BST_CHECKED;
  4674. // force a refresh on selection change
  4675. lastMode[Connection_CurSelPos] = -1;
  4676. ini_modified = 1;
  4677. if (Out->Encoder != -1 && Out->Handle != -1) {
  4678. SHOUTCAST_OUTPUT *Enc = &Encoder[Out->Encoder];
  4679. if (WaitForSingleObject(Enc_mutex[Out->Encoder], INFINITE) == WAIT_OBJECT_0) {
  4680. Enc->DisconnectOutput(Out->Handle, 1, 5);
  4681. ReleaseMutex(Enc_mutex[Out->Encoder]);
  4682. }
  4683. }
  4684. }
  4685. }
  4686. break;
  4687. case IDC_GENRES:
  4688. {
  4689. // build up a menu to allow the user to select only supported genres for use with YP
  4690. if (HIWORD(wParam) == BN_CLICKED) {
  4691. MY_T_OUTPUT *Out = &Output[Connection_CurSelPos];
  4692. HMENU hmenu = CreatePopupMenu(), submenu = 0;
  4693. RECT r;
  4694. GetWindowRect((HWND)lParam, &r);
  4695. for (unsigned int i = 0; i < ARRAYSIZE(genres); i++) {
  4696. MENUITEMINFO mii = {sizeof(mii), MIIM_ID | MIIM_STATE | MIIM_TYPE, MFT_STRING, 0, 1+i, 0, 0, 0, 0, 0, 0};
  4697. bool reAdd = false;
  4698. // fix up genres with & in it to work around menu accelerator display quirks
  4699. std::string str = genres[i].name;
  4700. if (str.find("&") != std::string::npos)
  4701. str.replace(str.find("&"),1,"&&");
  4702. mii.dwTypeData = (LPSTR)str.c_str();
  4703. if (genres[i].parent) {
  4704. if (genres[i].children) {
  4705. reAdd = true;
  4706. mii.fMask |= MIIM_SUBMENU;
  4707. submenu = mii.hSubMenu = CreatePopupMenu();
  4708. }
  4709. }
  4710. if (reAdd == false && !strcmpi(Out->Config.Genre, genres[i].name)) {
  4711. mii.fState = MFS_CHECKED;
  4712. }
  4713. InsertMenuItem((genres[i].parent ? hmenu : submenu), i, TRUE, &mii);
  4714. if (reAdd == true) {
  4715. mii.fMask -= MIIM_SUBMENU;
  4716. if (!strcmpi(Out->Config.Genre, genres[i].name)) {
  4717. mii.fState = MFS_CHECKED;
  4718. }
  4719. InsertMenuItem(submenu, i, TRUE, &mii);
  4720. }
  4721. }
  4722. int ret = TrackPopupMenu(hmenu, TPM_LEFTALIGN | TPM_TOPALIGN | TPM_RETURNCMD, r.left, r.bottom, 0, (HWND)hDlg, NULL);
  4723. if (ret > 0) {
  4724. int update = 0;
  4725. ret -= 1;
  4726. if (strcmp(genres[ret].name, Out->Config.Genre) != 0) {
  4727. update = 1;
  4728. SetDlgItemText(hDlg, IDC_GENRE, genres[ret].name);
  4729. lstrcpyn(Out->Config.Genre, genres[ret].name, ARRAYSIZE(Out->Config.Genre));
  4730. ini_modified = 1;
  4731. }
  4732. if (update && Out->Encoder != -1 && Out->Handle != -1) {
  4733. SHOUTCAST_OUTPUT *Enc = &Encoder[Out->Encoder];
  4734. if (WaitForSingleObject(Enc_mutex[Out->Encoder], INFINITE) == WAIT_OBJECT_0) {
  4735. Enc->DisconnectOutput(Out->Handle, 1, 5);
  4736. ReleaseMutex(Enc_mutex[Out->Encoder]);
  4737. }
  4738. }
  4739. }
  4740. DestroyMenu(hmenu);
  4741. }
  4742. }
  4743. break;
  4744. case IDC_DESCRIPTION:
  4745. {
  4746. if (HIWORD(wParam) == EN_UPDATE) {
  4747. MY_T_OUTPUT *Out = &Output[Connection_CurSelPos];
  4748. char temp[sizeof (Out->Config.Description)];
  4749. int update = 0;
  4750. GetWindowText((HWND) lParam, temp, ARRAYSIZE(temp));
  4751. if (strcmp(temp, Out->Config.Description) != 0) {
  4752. update = 1;
  4753. lstrcpyn(Out->Config.Description, temp, ARRAYSIZE(Out->Config.Description));
  4754. ini_modified = 1;
  4755. }
  4756. if (update && Out->Encoder != -1 && Out->Handle != -1) {
  4757. SHOUTCAST_OUTPUT *Enc = &Encoder[Out->Encoder];
  4758. if (WaitForSingleObject(Enc_mutex[Out->Encoder], INFINITE) == WAIT_OBJECT_0) {
  4759. Enc->DisconnectOutput(Out->Handle, 1, 5);
  4760. ReleaseMutex(Enc_mutex[Out->Encoder]);
  4761. }
  4762. }
  4763. } else if (HIWORD(wParam) == EN_SETFOCUS) {
  4764. PostMessage((HWND)lParam, EM_SETSEL, 0, (LPARAM)-1);
  4765. }
  4766. }
  4767. break;
  4768. case IDC_SERVERURL:
  4769. {
  4770. if (HIWORD(wParam) == EN_UPDATE) {
  4771. MY_T_OUTPUT *Out = &Output[Connection_CurSelPos];
  4772. char temp[sizeof (Out->Config.ServerURL)];
  4773. int update = 0;
  4774. GetWindowText((HWND) lParam, temp, ARRAYSIZE(temp));
  4775. if (strcmp(temp, Out->Config.ServerURL) != 0) {
  4776. update = 1;
  4777. lstrcpyn(Out->Config.ServerURL, temp, ARRAYSIZE(Out->Config.ServerURL));
  4778. ini_modified = 1;
  4779. }
  4780. if (update && Out->Encoder != -1 && Out->Handle != -1) {
  4781. SHOUTCAST_OUTPUT *Enc = &Encoder[Out->Encoder];
  4782. if (WaitForSingleObject(Enc_mutex[Out->Encoder], INFINITE) == WAIT_OBJECT_0) {
  4783. Enc->DisconnectOutput(Out->Handle, 1, 5);
  4784. ReleaseMutex(Enc_mutex[Out->Encoder]);
  4785. }
  4786. }
  4787. } else if (HIWORD(wParam) == EN_SETFOCUS) {
  4788. PostMessage((HWND)lParam, EM_SETSEL, 0, (LPARAM)-1);
  4789. }
  4790. }
  4791. break;
  4792. case IDC_AIM:
  4793. {
  4794. if (HIWORD(wParam) == EN_UPDATE) {
  4795. MY_T_OUTPUT *Out = &Output[Connection_CurSelPos];
  4796. char temp[sizeof (Out->Config.AIM)];
  4797. int update = 0;
  4798. GetWindowText((HWND) lParam, temp, ARRAYSIZE(temp));
  4799. if (strcmp(temp, Out->Config.AIM) != 0) {
  4800. update = 1;
  4801. lstrcpyn(Out->Config.AIM, temp, ARRAYSIZE(Out->Config.AIM));
  4802. ini_modified = 1;
  4803. }
  4804. if (update && Out->Encoder != -1 && Out->Handle != -1) {
  4805. SHOUTCAST_OUTPUT *Enc = &Encoder[Out->Encoder];
  4806. if (WaitForSingleObject(Enc_mutex[Out->Encoder], INFINITE) == WAIT_OBJECT_0) {
  4807. Enc->DisconnectOutput(Out->Handle, 1, 5);
  4808. ReleaseMutex(Enc_mutex[Out->Encoder]);
  4809. }
  4810. }
  4811. } else if (HIWORD(wParam) == EN_SETFOCUS) {
  4812. PostMessage((HWND)lParam, EM_SETSEL, 0, (LPARAM)-1);
  4813. }
  4814. }
  4815. break;
  4816. case IDC_ICQ:
  4817. {
  4818. if (HIWORD(wParam) == EN_UPDATE) {
  4819. MY_T_OUTPUT *Out = &Output[Connection_CurSelPos];
  4820. char temp[sizeof (Out->Config.ICQ)];
  4821. int update = 0;
  4822. GetWindowText((HWND) lParam, temp, ARRAYSIZE(temp));
  4823. if (strcmp(temp, Out->Config.ICQ) != 0) {
  4824. update = 1;
  4825. lstrcpyn(Out->Config.ICQ, temp, ARRAYSIZE(Out->Config.ICQ));
  4826. ini_modified = 1;
  4827. }
  4828. if (update && Out->Encoder != -1 && Out->Handle != -1) {
  4829. SHOUTCAST_OUTPUT *Enc = &Encoder[Out->Encoder];
  4830. if (WaitForSingleObject(Enc_mutex[Out->Encoder], INFINITE) == WAIT_OBJECT_0) {
  4831. Enc->DisconnectOutput(Out->Handle, 1, 5);
  4832. ReleaseMutex(Enc_mutex[Out->Encoder]);
  4833. }
  4834. }
  4835. } else if (HIWORD(wParam) == EN_SETFOCUS) {
  4836. PostMessage((HWND)lParam, EM_SETSEL, 0, (LPARAM)-1);
  4837. }
  4838. }
  4839. break;
  4840. case IDC_IRC:
  4841. {
  4842. if (HIWORD(wParam) == EN_UPDATE) {
  4843. MY_T_OUTPUT *Out = &Output[Connection_CurSelPos];
  4844. char temp[sizeof (Out->Config.IRC)];
  4845. int update = 0;
  4846. GetWindowText((HWND) lParam, temp, ARRAYSIZE(temp));
  4847. if (strcmp(temp, Out->Config.IRC) != 0) {
  4848. update = 1;
  4849. lstrcpyn(Out->Config.IRC, temp, ARRAYSIZE(Out->Config.IRC));
  4850. ini_modified = 1;
  4851. }
  4852. if (update && Out->Encoder != -1 && Out->Handle != -1) {
  4853. SHOUTCAST_OUTPUT *Enc = &Encoder[Out->Encoder];
  4854. if (WaitForSingleObject(Enc_mutex[Out->Encoder], INFINITE) == WAIT_OBJECT_0) {
  4855. Enc->DisconnectOutput(Out->Handle, 1, 5);
  4856. ReleaseMutex(Enc_mutex[Out->Encoder]);
  4857. }
  4858. }
  4859. } else if (HIWORD(wParam) == EN_SETFOCUS) {
  4860. PostMessage((HWND)lParam, EM_SETSEL, 0, (LPARAM)-1);
  4861. }
  4862. }
  4863. break;
  4864. }
  4865. }
  4866. break;
  4867. case WM_CTLCOLORSTATIC:
  4868. {
  4869. // this is used to update the header text of the options which need to be checked if there is a config error...
  4870. int id = GetDlgCtrlID((HWND)lParam);
  4871. if (id == IDC_ADDRESS_HEADER || id == IDC_PASSWORD_HEADER || id == IDC_NAME_HEADER || id == IDC_ENCODER_HEADER) {
  4872. int header_id[] = {0, 0, 0, IDC_ADDRESS_HEADER, IDC_PASSWORD_HEADER, IDC_NAME_HEADER, IDC_ENCODER_HEADER, 0};
  4873. if (lastMode[Connection_CurSelPos] >= 3 && lastMode[Connection_CurSelPos] <= 6 &&
  4874. header_id[lastMode[Connection_CurSelPos]] == id) {
  4875. SetTextColor((HDC)wParam, RGB(255,0,0));
  4876. }
  4877. }
  4878. }
  4879. break;
  4880. case WM_NOTIFY:
  4881. {
  4882. LPNMHDR pnmh = (LPNMHDR) lParam;
  4883. switch (LOWORD(wParam)) {
  4884. case IDC_TAB:
  4885. if (pnmh->code == TCN_SELCHANGE) {
  4886. int i;
  4887. KillTimer(hDlg, wnd[curtab].id);
  4888. curtab = SendMessage(pnmh->hwndFrom, TCM_GETCURSEL, 0, 0);
  4889. // send this to update the tab just incase we're showing invalid items
  4890. InvalidateRect(pnmh->hwndFrom, 0, 0);
  4891. ini_modified = 1;
  4892. if (wnd[curtab].timer_freq != 0) SetTimer(hDlg, wnd[curtab].id, wnd[curtab].timer_freq, NULL);
  4893. for (i = 0; i < num_tabwnds; i++) ShowWindow(wnd[i].hWnd, curtab == i ? SW_SHOW : SW_HIDE);
  4894. for (i = 0; i < num_inwnds; i++) ShowWindow(in_wnd[i].hWnd, i == InputDevice && curtab == 2 ? SW_SHOW : SW_HIDE);
  4895. for (i = 0; i < num_outwnds; i++) ShowWindow(out_wnd[i].hWnd, i == curouttab && curtab == 1 ? SW_SHOW : SW_HIDE);
  4896. // update the summary details when going back to it
  4897. if (curtab == 0) {
  4898. UpdateSummaryDetails(ListView_GetNextItem(GetDlgItem(wnd[0].hWnd, IDC_OUTPUTSTATUS), -1, LVNI_SELECTED));
  4899. } else if(curtab == 1) {
  4900. // force a refresh on selection change
  4901. lastMode[Connection_CurSelPos] = -1;
  4902. }
  4903. }
  4904. break;
  4905. case IDC_CONTAB:
  4906. if (pnmh->code == TCN_SELCHANGE) {
  4907. int i;
  4908. KillTimer(hDlg, out_wnd[curouttab].id);
  4909. curouttab = SendMessage(pnmh->hwndFrom, TCM_GETCURSEL, 0, 0);
  4910. // send this to update the tab just incase we're showing invalid items
  4911. InvalidateRect(pnmh->hwndFrom, 0, 0);
  4912. ini_modified = 1;
  4913. if (out_wnd[curouttab].timer_freq != 0) SetTimer(hDlg, out_wnd[curouttab].id, out_wnd[curouttab].timer_freq, NULL);
  4914. for (i = 0; i < num_outwnds; i++) ShowWindow(out_wnd[i].hWnd, i == curouttab ? SW_SHOW : SW_HIDE);
  4915. bool enable = (LOBYTE(Output[Connection_CurSelPos].Config.protocol) == 1);
  4916. EnableWindowDlgItem(out_wnd[1].hWnd, IDC_AIM, enable);
  4917. EnableWindowDlgItem(out_wnd[1].hWnd, IDC_IRC, enable);
  4918. EnableWindowDlgItem(out_wnd[1].hWnd, IDC_ICQ, enable);
  4919. }
  4920. break;
  4921. case IDC_METALIST:
  4922. if (pnmh->code == NM_DBLCLK) {
  4923. LPNMITEMACTIVATE lpnmitem = (LPNMITEMACTIVATE) lParam;
  4924. if (lpnmitem->iItem != -1 && WASABI_API_EXPLORERFINDFILE) {
  4925. wchar_t fn[MAX_PATH]= {0};
  4926. lstrcpynW(fn, lastFile, MAX_PATH);
  4927. if (!PathIsURLW(fn)) {
  4928. // this will attempt to find the path of the parent folder of the file selected
  4929. // as spc files in a rsn archive can display album art (with the compatibility
  4930. // wrapper) and so it should cope with such scenarios...
  4931. wchar_t *filews = fn + lstrlenW(fn) - 1;
  4932. while(filews && *filews && (*filews != L'.') && (filews != fn)){filews = CharPrevW(fn,filews);}
  4933. while(filews && *filews && (*filews != L',' && *filews != L':')){filews = CharNextW(filews);}
  4934. if (filews) *filews = 0;
  4935. filews = wcsstr(fn,L".rsn\\");
  4936. if(filews) {
  4937. *(filews+4) = 0;
  4938. }
  4939. WASABI_API_EXPLORERFINDFILE->AddFile(fn);
  4940. WASABI_API_EXPLORERFINDFILE->ShowFiles();
  4941. }
  4942. }
  4943. }
  4944. break;
  4945. case IDC_OUTPUTSTATUS:
  4946. // on double-click go to the output tab and select the output we used as the currently shown
  4947. if (pnmh->code == NM_DBLCLK) {
  4948. LPNMITEMACTIVATE lpnmitem = (LPNMITEMACTIVATE) lParam;
  4949. if (lpnmitem->iItem != -1 && lpnmitem->iSubItem != 0) {
  4950. // only change the viewed output mode if it is different, otherwise just switch tab
  4951. if (Connection_CurSelPos != lpnmitem->iItem) {
  4952. Connection_CurSelPos = lpnmitem->iItem;
  4953. // force a refresh on selection change
  4954. lastMode[Connection_CurSelPos] = -1;
  4955. SendDlgItemMessage(wnd[1].hWnd, IDC_OUTPUTLIST, LB_SETCURSEL, Connection_CurSelPos, 0);
  4956. SendMessage(wnd[1].hWnd, WM_COMMAND, MAKEWPARAM(IDC_OUTPUTLIST, LBN_SELCHANGE), (LPARAM) GetDlgItem(wnd[1].hWnd, IDC_OUTPUTLIST));
  4957. SetFocus(GetDlgItem(wnd[1].hWnd, IDC_OUTPUTLIST));
  4958. }
  4959. SetTab(1, hMainDLG, IDC_TAB);
  4960. }
  4961. } else if (pnmh->code == LVN_ITEMCHANGED) {
  4962. // on single-click / keyboard change, show some information about the stream such as most, encoder, etc (makes the page useful)
  4963. LPNMLISTVIEW lpnmitem = (LPNMLISTVIEW) lParam;
  4964. if (lpnmitem->iItem != -1) {
  4965. UpdateSummaryDetails(lpnmitem->iItem);
  4966. }
  4967. } else if(pnmh->code == LVN_KEYDOWN) {
  4968. LPNMLVKEYDOWN pnkd = (LPNMLVKEYDOWN) lParam;
  4969. // toggle state in the output list via 'space'
  4970. if (pnkd->wVKey == VK_SPACE) {
  4971. int item = ListView_GetNextItem(GetDlgItem(wnd[0].hWnd, IDC_OUTPUTSTATUS), -1, LVNI_SELECTED);
  4972. if (lastEnable[item]) {
  4973. int oldCurSelPos = Connection_CurSelPos;
  4974. Connection_CurSelPos = item;
  4975. SendMessage(wnd[1].hWnd, WM_COMMAND, MAKEWPARAM(IDC_CONNECT, BN_CLICKED), (LPARAM)GetDlgItem(wnd[1].hWnd, IDC_CONNECT));
  4976. Connection_CurSelPos = oldCurSelPos;
  4977. }
  4978. }
  4979. }
  4980. break;
  4981. }
  4982. }
  4983. break;
  4984. case WM_HSCROLL:
  4985. {
  4986. int curpos = SendMessage((HWND) lParam, TBM_GETPOS, 0, 0);
  4987. if (GetDlgItem(hDlg, IDC_MUSSLIDER) == (HWND) lParam) {
  4988. MusVol = curpos;
  4989. if (InputDevice == 1 && !FadeOut) setlev(MIXERLINE_COMPONENTTYPE_SRC_WAVEOUT, MusVol * 10);
  4990. wchar_t tmp[256] = {0};
  4991. if (curpos != 0) {
  4992. wchar_t temp[32] = {0};
  4993. int volume = (int) (20 * log10(curpos * 3276.));
  4994. StringCchPrintfW(tmp, ARRAYSIZE(tmp), LocalisedString(IDS_X_DB, temp, 32), volume - 90);
  4995. } else {
  4996. LocalisedString(IDS_INF_DB, tmp, 256);
  4997. }
  4998. SetDlgItemTextW(hDlg, IDC_MUSLEV1_TEXT, tmp);
  4999. } else if (GetDlgItem(hDlg, IDC_MUS2SLIDER) == (HWND) lParam) {
  5000. Mus2Vol = curpos;
  5001. if (InputDevice == 1 && FadeOut) setlev(MIXERLINE_COMPONENTTYPE_SRC_WAVEOUT, Mus2Vol * 10);
  5002. wchar_t tmp[256] = {0};
  5003. if (curpos != 0) {
  5004. wchar_t temp[32] = {0};
  5005. int volume = (int) (20 * log10(curpos * 3276.));
  5006. StringCchPrintfW(tmp, ARRAYSIZE(tmp), LocalisedString(IDS_X_DB, temp, 32), volume - 90);
  5007. } else {
  5008. LocalisedString(IDS_INF_DB, tmp, 256);
  5009. }
  5010. SetDlgItemTextW(hDlg, IDC_MUSLEV2_TEXT, tmp);
  5011. } else if (GetDlgItem(hDlg, IDC_MICSLIDER) == (HWND) lParam) {
  5012. MicVol = curpos;
  5013. int micsrc = Input_Device_ID >= 1 ? MIXERLINE_COMPONENTTYPE_SRC_LINE : MIXERLINE_COMPONENTTYPE_SRC_MICROPHONE;
  5014. // changed this so it will only change the capture device level if PTT is pressed
  5015. if (InputDevice == 1 && FadeOut) setlev(micsrc, MicVol *10);
  5016. wchar_t tmp[256] = {0};
  5017. if (curpos != 0) {
  5018. wchar_t temp[32] = {0};
  5019. int volume = (int) (20 * log10(curpos * 3276.));
  5020. StringCchPrintfW(tmp, ARRAYSIZE(tmp), LocalisedString(IDS_X_DB, temp, 32), volume - 90);
  5021. } else {
  5022. LocalisedString(IDS_INF_DB, tmp, 256);
  5023. }
  5024. SetDlgItemTextW(hDlg, IDC_MICLEV_TEXT, tmp);
  5025. } else if (GetDlgItem(hDlg, IDC_FADESLIDER) == (HWND) lParam) {
  5026. FadeTime = curpos;
  5027. wchar_t tmp[256] = {0}, temp[32] = {0};
  5028. StringCchPrintfW(tmp, ARRAYSIZE(tmp), LocalisedString(IDS_X_MS, temp, 32), curpos * 100);
  5029. SetDlgItemTextW(hDlg, IDC_FADETIME_TEXT, tmp);
  5030. } else if (GetDlgItem(hDlg, IDC_MICFADESLIDER) == (HWND) lParam) {
  5031. MicFadeTime = curpos;
  5032. wchar_t tmp[256] = {0}, temp[32] = {0};
  5033. StringCchPrintfW(tmp, ARRAYSIZE(tmp), LocalisedString(IDS_X_MS, temp, 32), curpos * 100);
  5034. SetDlgItemTextW(hDlg, IDC_MICFADETIME_TEXT, tmp);
  5035. }
  5036. }
  5037. break;
  5038. }
  5039. if (FALSE != DirectMouseWheel_ProcessDialogMessage(hDlg, uMsg, wParam, lParam)) {
  5040. return TRUE;
  5041. }
  5042. return 0;
  5043. }
  5044. LRESULT CALLBACK CallWndProc(int nCode, WPARAM wParam, LPARAM lParam) {
  5045. if (nCode == HC_ACTION) {
  5046. LPCWPSTRUCT msg = (LPCWPSTRUCT)lParam;
  5047. // catch the new file playing message and update the cached metadata
  5048. if (msg->message == WM_WA_IPC) {
  5049. if (msg->lParam == IPC_PLAYING_FILEW) {
  5050. DWORD diff = GetTickCount();
  5051. was_paused = 0;
  5052. play_duration = 0;
  5053. play_diff = diff;
  5054. was_playing = 1;
  5055. if (wcsnicmp(lastFile, (wchar_t*)msg->wParam, MAX_PATH)) {
  5056. PostMessage(hMainDLG, WM_USER, 0, nowPlayingID);
  5057. }
  5058. }
  5059. }
  5060. }
  5061. return (nowPlayingHook ? CallNextHookEx(nowPlayingHook, nCode, wParam, lParam) : 0);
  5062. }
  5063. LRESULT CALLBACK GetMsgProc(int nCode, WPARAM wParam, LPARAM lParam) {
  5064. if (nCode == HC_ACTION) {
  5065. LPMSG msg = (LPMSG)lParam;
  5066. // catch the new file playing message and update the cached metadata
  5067. if (msg->message == WM_WA_IPC) {
  5068. if (msg->lParam == IPC_CB_MISC && msg->wParam == IPC_CB_MISC_STATUS) {
  5069. isplaying = SendMessage(module.hwndParent, WM_WA_IPC, 0, IPC_ISPLAYING);
  5070. ProcessPlayingStatusUpdate();
  5071. } else if (msg->lParam == IPC_UPDTITLE) {
  5072. // attempt to keep a track of other title updates
  5073. // e.g. the re-streaming an already playing stream
  5074. wchar_t currentFile[MAX_PATH] = {0};
  5075. wchar_t *file=(wchar_t*)SendMessage(module.hwndParent, WM_WA_IPC,
  5076. SendMessage(module.hwndParent, WM_WA_IPC, 0, IPC_GETLISTPOS),
  5077. IPC_GETPLAYLISTFILEW);
  5078. wcsncpy(currentFile, (file ? file : L""), MAX_PATH);
  5079. if (!wcsnicmp(currentFile, lastFile, MAX_PATH)) {
  5080. // do a 1 second delay since it's likely Winamp will send
  5081. // this a few times so we reset the timer everytime so we
  5082. // only do a proper title update once everything settles
  5083. KillTimer(hMainDLG, 1337);
  5084. SetTimer(hMainDLG, 1337, 1000, NULL);
  5085. }
  5086. }
  5087. }
  5088. }
  5089. return (nowPlayingHook2 ? CallNextHookEx(nowPlayingHook2, nCode, wParam, lParam) : 0);
  5090. }
  5091. VOID CALLBACK TimerProc2(HWND hwnd, UINT uMsg, UINT_PTR idEvent, DWORD dwTime)
  5092. {
  5093. KillTimer(hwnd, idEvent);
  5094. SetForegroundWindow(hMainDLG);
  5095. }
  5096. void doConfig(HWND hwndParent) {
  5097. if (WASABI_API_SVC) {
  5098. if (!IsWindow(hMainDLG)) {
  5099. if (AGAVE_API_CONFIG) {
  5100. if (AGAVE_API_CONFIG->GetUnsigned(playbackConfigGroupGUID, L"bits", 16) > 16) {
  5101. wchar_t title[128] = {0}, message[512] = {0};
  5102. StringCchPrintfW(title, ARRAYSIZE(title), LocalisedString(IDS_PLUGIN_NAME, NULL, 0), APP_VersionW);
  5103. StringCchPrintfW(message, ARRAYSIZE(message), LocalisedString(IDS_24BIT_MODE_DETECTED, NULL, 0));
  5104. MessageBoxW(module.hwndParent, message, title, MB_ICONWARNING);
  5105. return;
  5106. }
  5107. }
  5108. // using this to lessen issues with new track events with higher bitrates leading to failures
  5109. if (!nowPlayingHook) {
  5110. nowPlayingHook = SetWindowsHookExW(WH_CALLWNDPROC, CallWndProc, instance, GetCurrentThreadId());
  5111. }
  5112. if (!nowPlayingHook2) {
  5113. nowPlayingHook2 = SetWindowsHookExW(WH_GETMESSAGE, GetMsgProc, instance, GetCurrentThreadId());
  5114. }
  5115. if (nowPlayingID == -1) {
  5116. nowPlayingID = SendMessage(hwndParent, WM_WA_IPC, (WPARAM)&"dsp_sc_np", IPC_REGISTER_WINAMP_IPCMESSAGE);
  5117. }
  5118. HWND hwnd = LocalisedCreateDialog(instance, IDD_DIALOG, hwndParent, DialogFunc, IDD_DIALOG);
  5119. SetWindowPos(hwnd, HWND_TOP, mainrect.left, mainrect.top, 0, 0, SWP_NOSIZE | SWP_SHOWWINDOW | SWP_NOSENDCHANGING);
  5120. SetTimer(hMainDLG, 999, 1, TimerProc2);
  5121. } else {
  5122. if (IsIconic(hMainDLG)) {
  5123. DialogFunc(hMainDLG, WM_SIZE, SIZE_RESTORED, 0);
  5124. ShowWindow(hMainDLG, SW_RESTORE);
  5125. ShowWindow(hMainDLG, SW_SHOW);
  5126. SetActiveWindow(hMainDLG);
  5127. }
  5128. SetForegroundWindow(hMainDLG);
  5129. }
  5130. }
  5131. }
  5132. VOID CALLBACK TimerProc(HWND hwnd, UINT uMsg, UINT_PTR idEvent, DWORD dwTime)
  5133. {
  5134. KillTimer(hwnd, idEvent);
  5135. doConfig(hwnd);
  5136. }
  5137. void Config(winampDSPModule *this_mod) {
  5138. // this will hold back opening the config dialog on loading until Winamp is in a ready state
  5139. // this resolves a partial fail to load i've often been seeing (plus from some users afaict)
  5140. SetTimer(this_mod->hwndParent, 999, 1, TimerProc);
  5141. }
  5142. int Init(winampDSPModule *this_mod) {
  5143. instance = this_mod->hDllInstance;
  5144. // this will hold back opening the config dialog on loading until Winamp is in a ready state
  5145. // this resolves a partial fail to load i've often been seeing (plus from some users afaict)
  5146. SetTimer(this_mod->hwndParent, 999, 1, TimerProc);
  5147. return 1;
  5148. }
  5149. int ModifySamples(winampDSPModule *this_mod, short int *samples, int numsamples, int bps, int nch, int srate) {
  5150. int numorig = numsamples;
  5151. //connect but only if we're meant to be i.e. there's at least 1 active output
  5152. if (InputDevice == 0) {
  5153. if (WaitForSingleObject(cf_mutex, INFINITE) == WAIT_OBJECT_0) {
  5154. // CT> Resample into the desired srate and nch if needed
  5155. // TODO check out the handling of this for 24-bit output
  5156. short cf_buf[256 * 1024] = {0};
  5157. if (srate != InputConfig.srate || nch != InputConfig.nch) {
  5158. char *s = (char *) samples;
  5159. int ns = numsamples * 2;
  5160. if (InputConfig.nch == 1) {
  5161. if (nch != 1 || bps != 16 || srate != (int) InputConfig.srate) {
  5162. if (nch == 2) {
  5163. int x;
  5164. int nns = MulDiv(numsamples, InputConfig.srate, srate);
  5165. int r = 0;
  5166. int dr = MulDiv(numsamples, 1 << 12, nns);
  5167. if (bps == 16)
  5168. {
  5169. for (x = 0; x < nns; x++) {
  5170. cf_buf[x] = samples[(r >> 12)*2] / 2 + samples[(r >> 12)*2 + 1] / 2;
  5171. r += dr;
  5172. }
  5173. }
  5174. else
  5175. {
  5176. for (x = 0; x < nns; x++) {
  5177. cf_buf[x] = ((((char *) samples)[(r >> 12)*2]^128) << 8) / 2 +
  5178. ((((char *) samples)[(r >> 12)*2 + 1]^128) << 8) / 2;
  5179. r += dr;
  5180. }
  5181. }
  5182. ns = nns * 2;
  5183. } else {
  5184. int x;
  5185. int nns = MulDiv(numsamples, InputConfig.srate, srate);
  5186. int r = 0;
  5187. int dr = MulDiv(numsamples, 1 << 12, nns);
  5188. if (bps == 16)
  5189. {
  5190. for (x = 0; x < nns; x++) {
  5191. cf_buf[x] = samples[r >> 12];
  5192. r += dr;
  5193. }
  5194. }
  5195. else
  5196. {
  5197. for (x = 0; x < nns; x++) {
  5198. cf_buf[x] = (((char *) samples)[r >> 12]^128) << 8;
  5199. r += dr;
  5200. }
  5201. }
  5202. ns = nns * 2;
  5203. }
  5204. s = (char *) cf_buf;
  5205. }
  5206. } else {
  5207. if (nch != 2 || bps != 16 || srate != (int) InputConfig.srate) {
  5208. if (nch == 2) {
  5209. int x;
  5210. int nns = MulDiv(numsamples, InputConfig.srate, srate);
  5211. int r = 0;
  5212. int dr = MulDiv(numsamples, 1 << 12, nns);
  5213. if (bps == 16)
  5214. {
  5215. for (x = 0; x < nns; x++) {
  5216. cf_buf[x * 2] = samples[(r >> 12)*2];
  5217. cf_buf[x * 2 + 1] = samples[(r >> 12)*2 + 1];
  5218. r += dr;
  5219. }
  5220. }
  5221. else
  5222. {
  5223. for (x = 0; x < nns; x++) {
  5224. cf_buf[x * 2] = (((char *) samples)[(r >> 12)*2]^128) << 8;
  5225. cf_buf[x * 2 + 1] = (((char *) samples)[(r >> 12)*2 + 1]^128) << 8;
  5226. r += dr;
  5227. }
  5228. ns = nns * 4;
  5229. }
  5230. } else {
  5231. int x;
  5232. int nns = MulDiv(numsamples, InputConfig.srate, srate);
  5233. int r = 0;
  5234. int dr = MulDiv(numsamples, 1 << 12, nns);
  5235. if (bps == 16)
  5236. {
  5237. for (x = 0; x < nns; x++) {
  5238. cf_buf[x * 2] = cf_buf[x * 2 + 1] = samples[r >> 12];
  5239. r += dr;
  5240. }
  5241. }
  5242. else
  5243. {
  5244. for (x = 0; x < nns; x++)
  5245. {
  5246. cf_buf[x * 2] = cf_buf[x * 2 + 1] = (((char *) samples)[r >> 12]^128) << 8;
  5247. r += dr;
  5248. }
  5249. ns = nns * 4;
  5250. }
  5251. }
  5252. s = (char *) cf_buf;
  5253. }
  5254. else ns *= 2;
  5255. }
  5256. samples = (short *) s;
  5257. numsamples = ns / (InputConfig.nch * 2);
  5258. }
  5259. if (!VU.update) {
  5260. for (int j = 0; j < numsamples; j++) {
  5261. if (VU.vu_l < samples[j]) VU.vu_l = samples[j];
  5262. if (InputConfig.nch == 2) {
  5263. if (VU.vu_r < samples[j + 1]) VU.vu_r = samples[j + 1];
  5264. j++;
  5265. }
  5266. }
  5267. if (InputConfig.nch == 1) VU.vu_r = VU.vu_l;
  5268. VU.update = 1;
  5269. }
  5270. Crossfader->put(samples, numsamples);
  5271. ReleaseMutex(cf_mutex);
  5272. }
  5273. }
  5274. return numorig;
  5275. }
  5276. void Quit(winampDSPModule *this_mod) {
  5277. doQuit();
  5278. }