Click here to Skip to main content
12,624,121 members (34,081 online)
Click here to Skip to main content

Stats

29.9K views
406 downloads
21 bookmarked
Posted

Multidevice ASIO output plugin for WinAMP

, 13 Feb 2009 CDDL
A tiny WinAMP output DLL that uses a C++ replacement of the official ASIO SDK that supports multiple ASIO devices.
#include "WAOutModule.hpp"

#include "debugMacros.hpp"

namespace WinAMP
{

namespace OutModule
{

//  WinAMPOutModuleSingleton.
//************************************
// Method:    singleton
// FullName:  WinAMP::OutModule::WAOutModule::singleton
// Access:    public static 
//************************************

WAOutModule WAOutModule::WinAMPOutModule;
WAOutModule & WAOutModule::singleton() { return WinAMPOutModule; }


//************************************
// Method:    WAOutModule
// FullName:  WinAMP::OutModule::WAOutModule::WAOutModule
// Access:    private 
//************************************

WAOutModule::WAOutModule()
{
    version        = OUT_VER;

    description    = const_cast<char *>( WAOutModuleDescription() );
    id             = WAOutModuleID();

    hMainWindow    = NULL;
    hDllInstance   = NULL;

    Config         = &OutModule::ConfigDialog;
    About          = &OutModule::About;
    Init           = &OutModule::Init;
    Quit           = &OutModule::Quit;
    Open           = &OutModule::Open;
    Close          = &OutModule::Close;
    Write          = NULL; // &OutModule::Write;
    CanWrite       = &OutModule::CanWrite;
    IsPlaying      = &OutModule::IsPlaying;
    Pause          = &OutModule::Pause;
    SetVolume      = NULL; // &WAOutModule::SetVolumeWaveOut;
    SetPan         = NULL; // &WAOutModule::SetPanWaveOut;
    Flush          = &OutModule::Flush;
    GetOutputTime  = &OutModule::GetOutputTime;
    GetWrittenTime = &OutModule::GetWrittenTime;
}


//************************************
// Method:    SetVolumeMixer
// FullName:  WinAMP::OutModule::WAOutModule::SetVolumeMixer
// Access:    public 
//************************************
//  SetVolume mixerAPI implementation.
//************************************

void __cdecl WAOutModule::SetVolumeMixer( int const volume )
{
    assert( (volume >= 0 && volume <= 255) || volume == -666 );
    if ( volume == -666 )
        return;

    // (todo) This is a quick implementation that makes redundant calls every
    //        time (only the final mixerSetControlDetails() should be required)
    //        only to avoid having state/becoming an object. It should be
    //        refactored to get the necessary information only once and use it
    //        afterwards.

    #pragma comment( lib, "Winmm.lib" )
    MIXERLINE xline; xline.cbStruct = sizeof( MIXERLINE ); xline.dwComponentType = MIXERLINE_COMPONENTTYPE_DST_SPEAKERS;
    VERIFY( ::mixerGetLineInfo( HMIXEROBJ(), &xline, MIXER_GETLINEINFOF_COMPONENTTYPE | MIXER_OBJECTF_MIXER ) == MMSYSERR_NOERROR );

    MIXERCONTROL xcontrol;
    MIXERLINECONTROLS xcontrols =
    {
        sizeof( MIXERLINECONTROLS ),        // xcontrols.cbStruct
        xline.dwLineID,                     // xcontrols.dwLineID
        MIXERCONTROL_CONTROLTYPE_VOLUME,    // xcontrols.dwControlType
        1,                                  // xcontrols.cControls = xline.cControls;
        sizeof( MIXERCONTROL ),             // xcontrols.cbmxctrl
        &xcontrol                           // xcontrols.pamxctrl
    };
    VERIFY( ::mixerGetLineControls( HMIXEROBJ(), &xcontrols, MIXER_GETLINECONTROLSF_ONEBYTYPE | MIXER_OBJECTF_MIXER ) == MMSYSERR_NOERROR );


    static MIXERCONTROLDETAILS_UNSIGNED detail;
    static MIXERCONTROLDETAILS detalis =
    {
        sizeof( MIXERCONTROLDETAILS ),              // detalis.cbStruct
        1,                                          // detalis.dwControlID
        1,                                          // detalis.cChannels
        NULL,                                       // detalis.hwndOwner
        sizeof( MIXERCONTROLDETAILS_UNSIGNED ),     // detalis.cbDetails
        &detail                                     // detalis.paDetails
    };
    detalis.dwControlID = xcontrol.dwControlID;

    detail.dwValue = volume << 8 | 0xFF;

    VERIFY( ::mixerSetControlDetails( HMIXEROBJ(), &detalis, MIXER_OBJECTF_WAVEOUT | MIXER_SETCONTROLDETAILSF_VALUE ) == MMSYSERR_NOERROR );
}


//************************************
// Method:    SetPanMixer
// FullName:  WinAMP::OutModule::WAOutModule::SetPanMixer
// Access:    public 
//************************************
//  SetPan mixerAPI implementation.
//************************************

void WAOutModule::SetPanMixer( int const pan )
{
    //  I could not get the panning through the MixerAPI to work no matter what.
    // (todo) try to fix it.
    SetPanVoid( pan );
}


//************************************
// Method:    SetPanWaveOut
// FullName:  WinAMP::OutModule::WAOutModule::SetPanWaveOut
// Access:    public 
//************************************
//  SetPan waveOut/MME implementation.
//************************************

void WAOutModule::SetPanWaveOut( int const pan )
{
    assert( pan >= -128 && pan < 128 );

    DWORD currentGain;
    VERIFY( ::waveOutGetVolume( HWAVEOUT(), &currentGain ) == MMSYSERR_NOERROR );
    assert( currentGain < 65536 );

    DWORD leftGain, rightGain;
    if ( pan == 0 )
        leftGain = rightGain = currentGain;
    else if ( pan < 0 )
    {
        leftGain  = currentGain * pan / (-128);
        rightGain = currentGain;
    }
    else
    {
        leftGain  = currentGain;
        rightGain = currentGain * pan / 128;
    }

    // (todo) Investigate why a direct VERIFY does not work here (!?).
    MMRESULT const setResult( ::waveOutSetVolume( HWAVEOUT(), leftGain | rightGain << 16 ) );
    assert( setResult == MMSYSERR_NOERROR ); setResult;
}


//************************************
// Method:    SetVolumeWaveOut
// FullName:  WinAMP::OutModule::WAOutModule::SetVolumeWaveOut
// Access:    public 
//************************************
//  SetVolume waveOut/MME implementation.
//************************************

void __cdecl WAOutModule::SetVolumeWaveOut( int const volume )
{
    assert( (volume >= 0 && volume <= 255) || volume == -666 );
    if ( volume == -666 )
        return;

    DWORD const volume16bit( volume << 8 );
    // (todo) Investigate why a direct VERIFY does not work here (!?).
    MMRESULT const setResult( ::waveOutSetVolume( 0, volume16bit | volume16bit << 16 ) );
    assert( setResult == MMSYSERR_NOERROR ); setResult;
}

}   // namespace OutModule


HWND      WinAMPWindowHandle() { return OutModule::WAOutModule::singleton().WinAMPWindow(); }
HINSTANCE DLLInstanceHandle () { return OutModule::WAOutModule::singleton().DLLInstance (); }

}   // namespace WinAMP


//  The one exported function required by WinAMP.
extern "C"
{
    __declspec(dllexport) WinAMP::OutModule::Out_Module * __cdecl winampGetOutModule()
    {
        return &WinAMP::OutModule::WAOutModule::singleton().getWAOutModule();
    }
}

By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.

If a file you wish to view isn't highlighted, and is a text file (not binary), please let us know and we'll add colourisation support for it.

License

This article, along with any associated source code and files, is licensed under The Common Development and Distribution License (CDDL)

Share

About the Author

Domagoj Šarić
Software Developer Little Endian Ltd.
Croatia Croatia
No Biography provided

You may also be interested in...

Pro
| Advertise | Privacy | Terms of Use | Mobile
Web02 | 2.8.161128.1 | Last Updated 13 Feb 2009
Article Copyright 2009 by Domagoj Šarić
Everything else Copyright © CodeProject, 1999-2016
Layout: fixed | fluid