pa_win_waveformat.c (6385B)
1 /* 2 * PortAudio Portable Real-Time Audio Library 3 * Windows WAVEFORMAT* data structure utilities 4 * portaudio.h should be included before this file. 5 * 6 * Copyright (c) 2007 Ross Bencina 7 * 8 * Permission is hereby granted, free of charge, to any person obtaining 9 * a copy of this software and associated documentation files 10 * (the "Software"), to deal in the Software without restriction, 11 * including without limitation the rights to use, copy, modify, merge, 12 * publish, distribute, sublicense, and/or sell copies of the Software, 13 * and to permit persons to whom the Software is furnished to do so, 14 * subject to the following conditions: 15 * 16 * The above copyright notice and this permission notice shall be 17 * included in all copies or substantial portions of the Software. 18 * 19 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 20 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 21 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 22 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR 23 * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF 24 * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 25 * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 26 */ 27 28 /* 29 * The text above constitutes the entire PortAudio license; however, 30 * the PortAudio community also makes the following non-binding requests: 31 * 32 * Any person wishing to distribute modifications to the Software is 33 * requested to send the modifications to the original developer so that 34 * they can be incorporated into the canonical version. It is also 35 * requested that these non-binding requests be included along with the 36 * license above. 37 */ 38 39 #include <windows.h> 40 #include <mmsystem.h> 41 #if defined(WINAPI_FAMILY) && (WINAPI_FAMILY == WINAPI_FAMILY_APP) 42 #include <mmreg.h> /* for WAVEFORMATEX */ 43 #endif 44 45 #include "portaudio.h" 46 #include "pa_win_waveformat.h" 47 48 49 #if !defined(WAVE_FORMAT_EXTENSIBLE) 50 #define WAVE_FORMAT_EXTENSIBLE 0xFFFE 51 #endif 52 53 54 static GUID pawin_ksDataFormatSubtypeGuidBase = 55 { (USHORT)(WAVE_FORMAT_PCM), 0x0000, 0x0010, 0x80, 0x00, 0x00, 0xaa, 0x00, 0x38, 0x9b, 0x71 }; 56 57 58 int PaWin_SampleFormatToLinearWaveFormatTag( PaSampleFormat sampleFormat ) 59 { 60 if( sampleFormat == paFloat32 ) 61 return PAWIN_WAVE_FORMAT_IEEE_FLOAT; 62 63 return PAWIN_WAVE_FORMAT_PCM; 64 } 65 66 67 void PaWin_InitializeWaveFormatEx( PaWinWaveFormat *waveFormat, 68 int numChannels, PaSampleFormat sampleFormat, int waveFormatTag, double sampleRate ) 69 { 70 WAVEFORMATEX *waveFormatEx = (WAVEFORMATEX*)waveFormat; 71 int bytesPerSample = Pa_GetSampleSize(sampleFormat); 72 unsigned long bytesPerFrame = numChannels * bytesPerSample; 73 74 waveFormatEx->wFormatTag = waveFormatTag; 75 waveFormatEx->nChannels = (WORD)numChannels; 76 waveFormatEx->nSamplesPerSec = (DWORD)sampleRate; 77 waveFormatEx->nAvgBytesPerSec = waveFormatEx->nSamplesPerSec * bytesPerFrame; 78 waveFormatEx->nBlockAlign = (WORD)bytesPerFrame; 79 waveFormatEx->wBitsPerSample = bytesPerSample * 8; 80 waveFormatEx->cbSize = 0; 81 } 82 83 84 void PaWin_InitializeWaveFormatExtensible( PaWinWaveFormat *waveFormat, 85 int numChannels, PaSampleFormat sampleFormat, int waveFormatTag, double sampleRate, 86 PaWinWaveFormatChannelMask channelMask ) 87 { 88 WAVEFORMATEX *waveFormatEx = (WAVEFORMATEX*)waveFormat; 89 int bytesPerSample = Pa_GetSampleSize(sampleFormat); 90 unsigned long bytesPerFrame = numChannels * bytesPerSample; 91 GUID guid; 92 93 waveFormatEx->wFormatTag = WAVE_FORMAT_EXTENSIBLE; 94 waveFormatEx->nChannels = (WORD)numChannels; 95 waveFormatEx->nSamplesPerSec = (DWORD)sampleRate; 96 waveFormatEx->nAvgBytesPerSec = waveFormatEx->nSamplesPerSec * bytesPerFrame; 97 waveFormatEx->nBlockAlign = (WORD)bytesPerFrame; 98 waveFormatEx->wBitsPerSample = bytesPerSample * 8; 99 waveFormatEx->cbSize = 22; 100 101 *((WORD*)&waveFormat->fields[PAWIN_INDEXOF_WVALIDBITSPERSAMPLE]) = 102 waveFormatEx->wBitsPerSample; 103 104 *((DWORD*)&waveFormat->fields[PAWIN_INDEXOF_DWCHANNELMASK]) = channelMask; 105 106 guid = pawin_ksDataFormatSubtypeGuidBase; 107 guid.Data1 = (USHORT)waveFormatTag; 108 *((GUID*)&waveFormat->fields[PAWIN_INDEXOF_SUBFORMAT]) = guid; 109 } 110 111 PaWinWaveFormatChannelMask PaWin_DefaultChannelMask( int numChannels ) 112 { 113 switch( numChannels ){ 114 case 1: 115 return PAWIN_SPEAKER_MONO; 116 case 2: 117 return PAWIN_SPEAKER_STEREO; 118 case 3: 119 return PAWIN_SPEAKER_FRONT_LEFT | PAWIN_SPEAKER_FRONT_CENTER | PAWIN_SPEAKER_FRONT_RIGHT; 120 case 4: 121 return PAWIN_SPEAKER_QUAD; 122 case 5: 123 return PAWIN_SPEAKER_QUAD | PAWIN_SPEAKER_FRONT_CENTER; 124 case 6: 125 /* The meaning of the PAWIN_SPEAKER_5POINT1 flag has changed over time: 126 http://msdn2.microsoft.com/en-us/library/aa474707.aspx 127 We use PAWIN_SPEAKER_5POINT1 (not PAWIN_SPEAKER_5POINT1_SURROUND) 128 because on some cards (eg Audigy) PAWIN_SPEAKER_5POINT1_SURROUND 129 results in a virtual mixdown placing the rear output in the 130 front _and_ rear speakers. 131 */ 132 return PAWIN_SPEAKER_5POINT1; 133 /* case 7: */ 134 case 8: 135 /* RoBi: PAWIN_SPEAKER_7POINT1_SURROUND fits normal surround sound setups better than PAWIN_SPEAKER_7POINT1, f.i. NVidia HDMI Audio 136 output is silent on channels 5&6 with NVidia drivers, and channel 7&8 with Micrsoft HD Audio driver using PAWIN_SPEAKER_7POINT1. 137 With PAWIN_SPEAKER_7POINT1_SURROUND both setups work OK. */ 138 return PAWIN_SPEAKER_7POINT1_SURROUND; 139 } 140 141 /* Apparently some Audigy drivers will output silence 142 if the direct-out constant (0) is used. So this is not ideal. 143 144 RoBi 2012-12-19: Also, NVidia driver seem to output garbage instead. Again not very ideal. 145 */ 146 return PAWIN_SPEAKER_DIRECTOUT; 147 148 /* Note that Alec Rogers proposed the following as an alternate method to 149 generate the default channel mask, however it doesn't seem to be an improvement 150 over the above, since some drivers will matrix outputs mapping to non-present 151 speakers accross multiple physical speakers. 152 153 if(nChannels==1) { 154 pwfFormat->dwChannelMask = SPEAKER_FRONT_CENTER; 155 } 156 else { 157 pwfFormat->dwChannelMask = 0; 158 for(i=0; i<nChannels; i++) 159 pwfFormat->dwChannelMask = (pwfFormat->dwChannelMask << 1) | 0x1; 160 } 161 */ 162 }