Cinnamon audio library
Revision | a3f115b38c8e33bdddfdef53aa6be43fc3c37a9f (tree) |
---|---|
Zeit | 2020-01-05 07:08:05 |
Autor | AlaskanEmily <emily@alas...> |
Commiter | AlaskanEmily |
Add Cin_DriverSupports* API implementation for DirectSound
This removes the dummied out implmentation previously used.
Refactor some of the format translation from Cinnamon to DirectSound structures
in cin_dsound_sound so that they can be used from cin_dsound for the
Cin_DriverSupports* API.
Add slightly ugly getter in cin_dsound_driver to allow the IDirectSound8 object
to be used from cin_dsound for the Cin_DriverSupports* API.
@@ -12,6 +12,35 @@ | ||
12 | 12 | |
13 | 13 | /////////////////////////////////////////////////////////////////////////////// |
14 | 14 | |
15 | +CIN_PRIVATE(bool) cin_supports_format(IDirectSound8 *dsound, | |
16 | + unsigned rate, | |
17 | + unsigned channels, | |
18 | + enum Cin_Format sample_type){ | |
19 | + | |
20 | + WAVEFORMATEXTENSIBLE fmt; | |
21 | + DSBUFFERDESC buffer_desc; | |
22 | + Cin_Sound::CreateWaveFormat(rate, channels, sample_type, fmt); | |
23 | + | |
24 | + buffer_desc.dwSize = sizeof(DSBUFFERDESC); | |
25 | + buffer_desc.dwFlags = DSBCAPS_GLOBALFOCUS; | |
26 | + // Arbitrary, medium-sized power-of-two size | |
27 | + buffer_desc.dwBufferBytes = 4096; | |
28 | + buffer_desc.dwReserved = 0; | |
29 | + buffer_desc.lpwfxFormat = &fmt.Format; | |
30 | + buffer_desc.guid3DAlgorithm = DS3DALG_DEFAULT; | |
31 | + | |
32 | + IDirectSoundBuffer *buffer; | |
33 | + if(dsound->CreateSoundBuffer(&buffer_desc, &buffer, NULL) != DS_OK){ | |
34 | + return false; | |
35 | + } | |
36 | + else{ | |
37 | + buffer->Release(); | |
38 | + return true; | |
39 | + } | |
40 | +} | |
41 | + | |
42 | +/////////////////////////////////////////////////////////////////////////////// | |
43 | + | |
15 | 44 | CIN_EXPORT(unsigned) Cin_StructDriverSize(void){ |
16 | 45 | return sizeof(Cin_Driver); |
17 | 46 | } |
@@ -36,8 +65,26 @@ CIN_EXPORT(enum Cin_DriverError) Cin_DriverSupportsFormat( | ||
36 | 65 | enum Cin_Format format, |
37 | 66 | unsigned num_channels){ |
38 | 67 | |
39 | - // TODO! | |
40 | - return Cin_eDriverSuccess; | |
68 | + if(drv == NULL) | |
69 | + return Cin_eDriverFailure; | |
70 | + | |
71 | + if(IDirectSound8 *const dsound = | |
72 | + const_cast<Cin_Driver*>(drv)->getDirectSound()){ | |
73 | + | |
74 | + // Try to create a buffer with this format and num channels, at | |
75 | + // either 44100 or 48000 Hz. | |
76 | + if(cin_supports_format(dsound, 44100, num_channels, format) || | |
77 | + cin_supports_format(dsound, 48000, num_channels, format)){ | |
78 | + | |
79 | + return Cin_eDriverSuccess; | |
80 | + } | |
81 | + else{ | |
82 | + return Cin_eDriverFailure; | |
83 | + } | |
84 | + } | |
85 | + else{ | |
86 | + return Cin_eDriverFailure; | |
87 | + } | |
41 | 88 | } |
42 | 89 | |
43 | 90 | /////////////////////////////////////////////////////////////////////////////// |
@@ -46,8 +93,25 @@ CIN_EXPORT(enum Cin_DriverError) Cin_DriverSupportsSampleRate( | ||
46 | 93 | const struct Cin_Driver *drv, |
47 | 94 | unsigned rate){ |
48 | 95 | |
49 | - // TODO! | |
50 | - return Cin_eDriverSuccess; | |
96 | + if(drv == NULL) | |
97 | + return Cin_eDriverFailure; | |
98 | + | |
99 | + if(IDirectSound8 *const dsound = | |
100 | + const_cast<Cin_Driver*>(drv)->getDirectSound()){ | |
101 | + | |
102 | + // Try to create a buffer with this rate and basic setup | |
103 | + if(cin_supports_format(dsound, rate, 2, Cin_eFormatS16) || | |
104 | + cin_supports_format(dsound, rate, 2, Cin_eFormatFloat32)){ | |
105 | + | |
106 | + return Cin_eDriverSuccess; | |
107 | + } | |
108 | + else{ | |
109 | + return Cin_eDriverFailure; | |
110 | + } | |
111 | + } | |
112 | + else{ | |
113 | + return Cin_eDriverFailure; | |
114 | + } | |
51 | 115 | } |
52 | 116 | |
53 | 117 | /////////////////////////////////////////////////////////////////////////////// |
@@ -33,6 +33,9 @@ public: | ||
33 | 33 | Cin_Driver(); |
34 | 34 | ~Cin_Driver(); |
35 | 35 | |
36 | + // This is only used for testing if a format/sample rate is supported. | |
37 | + inline IDirectSound8 *getDirectSound() { return m_dsound; } | |
38 | + | |
36 | 39 | void createSound(Cin_Sound *out, const Cin_Loader &ld); |
37 | 40 | |
38 | 41 | }; |
@@ -17,97 +17,11 @@ | ||
17 | 17 | |
18 | 18 | Cin_Sound::Cin_Sound(IDirectSound8 *dsound, const Cin_Loader &ld) |
19 | 19 | : m_dsound(dsound){ |
20 | - | |
21 | - const unsigned sample_rate = ld.sample_rate; | |
22 | - const unsigned channels = ld.channels; | |
23 | - const enum Cin_Format format = ld.format; | |
24 | - | |
20 | + | |
25 | 21 | WAVEFORMATEXTENSIBLE fmt; |
26 | -#ifndef NDEBUG | |
27 | - // Poison the uninitialized format | |
28 | - memset((void*)&fmt, 0xFF, sizeof(fmt)); | |
29 | -#endif | |
30 | - | |
31 | - // Set format tag | |
32 | - switch(format){ | |
33 | - case Cin_eFormatS8: | |
34 | - case Cin_eFormatS16: | |
35 | - case Cin_eFormatS32: | |
36 | - fmt.Format.cbSize = 0; | |
37 | - fmt.Format.wFormatTag = WAVE_FORMAT_PCM; | |
38 | - break; | |
39 | - case Cin_eFormatFloat32: | |
40 | - case Cin_eFormatFloat64: | |
41 | - case Cin_eFormatULaw8: | |
42 | - fmt.Format.wFormatTag = WAVE_FORMAT_EXTENSIBLE; | |
43 | - fmt.Format.cbSize = sizeof(fmt) - sizeof(fmt.Format); | |
44 | - break; | |
45 | - } | |
46 | - | |
47 | - unsigned bytes_per_sample = 0; | |
48 | - switch(format){ | |
49 | - case Cin_eFormatS8: | |
50 | - bytes_per_sample = 1; | |
51 | - break; | |
52 | - case Cin_eFormatS16: | |
53 | - bytes_per_sample = 2; | |
54 | - break; | |
55 | - case Cin_eFormatS32: | |
56 | - bytes_per_sample = 4; | |
57 | - break; | |
58 | - case Cin_eFormatFloat32: | |
59 | - bytes_per_sample = 4; | |
60 | - fmt.SubFormat = KSDATAFORMAT_SUBTYPE_IEEE_FLOAT; | |
61 | - fmt.Samples.wValidBitsPerSample = 32; | |
62 | - break; | |
63 | - case Cin_eFormatFloat64: | |
64 | - bytes_per_sample = 8; | |
65 | - fmt.SubFormat = KSDATAFORMAT_SUBTYPE_IEEE_FLOAT; | |
66 | - fmt.Samples.wValidBitsPerSample = 64; | |
67 | - break; | |
68 | - case Cin_eFormatULaw8: | |
69 | - bytes_per_sample = 1; | |
70 | - fmt.SubFormat = KSDATAFORMAT_SUBTYPE_MULAW; | |
71 | - fmt.Samples.wValidBitsPerSample = 8; | |
72 | - break; | |
73 | - } | |
74 | - | |
75 | - // Set channels | |
76 | - fmt.Format.nChannels = channels; | |
77 | - if(fmt.Format.wFormatTag != WAVE_FORMAT_PCM){ | |
78 | - switch(channels){ | |
79 | - case 1: | |
80 | - fmt.dwChannelMask = KSAUDIO_SPEAKER_MONO; | |
81 | - break; | |
82 | - case 2: | |
83 | - fmt.dwChannelMask = KSAUDIO_SPEAKER_STEREO; | |
84 | - break; | |
85 | - case 4: | |
86 | - fmt.dwChannelMask = KSAUDIO_SPEAKER_QUAD; | |
87 | - break; | |
88 | - case 6: | |
89 | - fmt.dwChannelMask = KSAUDIO_SPEAKER_5POINT1_SURROUND; | |
90 | - break; | |
91 | - default: | |
92 | - fmt.dwChannelMask = 0; | |
93 | - } | |
94 | - } | |
95 | - | |
96 | - // Set sample rate | |
97 | - fmt.Format.nSamplesPerSec = sample_rate; | |
98 | - | |
99 | - // Block align | |
100 | - const unsigned align = channels * bytes_per_sample; | |
101 | - const unsigned bytes_per_sec = align * sample_rate; | |
102 | - fmt.Format.nBlockAlign = align; | |
103 | - | |
104 | - fmt.Format.nAvgBytesPerSec = bytes_per_sec; | |
105 | - | |
106 | - // Set bits per sample | |
107 | - fmt.Format.wBitsPerSample = bytes_per_sample << 3; | |
108 | - | |
22 | + CreateWaveFormat(ld.sample_rate, ld.channels, ld.format, fmt); | |
23 | + | |
109 | 24 | // Check the size of the loader data. |
110 | - | |
111 | 25 | const unsigned byte_size = ld.bytes_placed; |
112 | 26 | #ifndef NDEBUG |
113 | 27 | { |
@@ -119,7 +33,6 @@ Cin_Sound::Cin_Sound(IDirectSound8 *dsound, const Cin_Loader &ld) | ||
119 | 33 | } |
120 | 34 | #endif |
121 | 35 | |
122 | - | |
123 | 36 | DSBUFFERDESC descriptor; |
124 | 37 | descriptor.dwSize = sizeof(DSBUFFERDESC); |
125 | 38 | descriptor.dwFlags = DSBCAPS_GLOBALFOCUS; |
@@ -174,5 +87,95 @@ void Cin_Sound::stop(){ | ||
174 | 87 | if(m_buffer != NULL) |
175 | 88 | m_buffer->Stop(); |
176 | 89 | } |
90 | +/////////////////////////////////////////////////////////////////////////////// | |
91 | + | |
92 | +void Cin_Sound::CreateWaveFormat(unsigned sample_rate, | |
93 | + unsigned channels, | |
94 | + enum Cin_Format format, | |
95 | + WAVEFORMATEXTENSIBLE &out_fmt){ | |
96 | + | |
97 | +#ifndef NDEBUG | |
98 | + // Poison the uninitialized format | |
99 | + memset((void*)&out_fmt, 0xFF, sizeof(WAVEFORMATEXTENSIBLE)); | |
100 | +#endif | |
101 | + | |
102 | + // Set format tag | |
103 | + switch(format){ | |
104 | + case Cin_eFormatS8: | |
105 | + case Cin_eFormatS16: | |
106 | + case Cin_eFormatS32: | |
107 | + out_fmt.Format.cbSize = 0; | |
108 | + out_fmt.Format.wFormatTag = WAVE_FORMAT_PCM; | |
109 | + break; | |
110 | + case Cin_eFormatFloat32: | |
111 | + case Cin_eFormatFloat64: | |
112 | + case Cin_eFormatULaw8: | |
113 | + out_fmt.Format.wFormatTag = WAVE_FORMAT_EXTENSIBLE; | |
114 | + out_fmt.Format.cbSize = sizeof(out_fmt) - sizeof(out_fmt.Format); | |
115 | + break; | |
116 | + } | |
117 | + | |
118 | + unsigned bytes_per_sample = 0; | |
119 | + switch(format){ | |
120 | + case Cin_eFormatS8: | |
121 | + bytes_per_sample = 1; | |
122 | + break; | |
123 | + case Cin_eFormatS16: | |
124 | + bytes_per_sample = 2; | |
125 | + break; | |
126 | + case Cin_eFormatS32: | |
127 | + bytes_per_sample = 4; | |
128 | + break; | |
129 | + case Cin_eFormatFloat32: | |
130 | + bytes_per_sample = 4; | |
131 | + out_fmt.SubFormat = KSDATAFORMAT_SUBTYPE_IEEE_FLOAT; | |
132 | + out_fmt.Samples.wValidBitsPerSample = 32; | |
133 | + break; | |
134 | + case Cin_eFormatFloat64: | |
135 | + bytes_per_sample = 8; | |
136 | + out_fmt.SubFormat = KSDATAFORMAT_SUBTYPE_IEEE_FLOAT; | |
137 | + out_fmt.Samples.wValidBitsPerSample = 64; | |
138 | + break; | |
139 | + case Cin_eFormatULaw8: | |
140 | + bytes_per_sample = 1; | |
141 | + out_fmt.SubFormat = KSDATAFORMAT_SUBTYPE_MULAW; | |
142 | + out_fmt.Samples.wValidBitsPerSample = 8; | |
143 | + break; | |
144 | + } | |
145 | + | |
146 | + // Set channels | |
147 | + out_fmt.Format.nChannels = channels; | |
148 | + if(out_fmt.Format.wFormatTag != WAVE_FORMAT_PCM){ | |
149 | + switch(channels){ | |
150 | + case 1: | |
151 | + out_fmt.dwChannelMask = KSAUDIO_SPEAKER_MONO; | |
152 | + break; | |
153 | + case 2: | |
154 | + out_fmt.dwChannelMask = KSAUDIO_SPEAKER_STEREO; | |
155 | + break; | |
156 | + case 4: | |
157 | + out_fmt.dwChannelMask = KSAUDIO_SPEAKER_QUAD; | |
158 | + break; | |
159 | + case 6: | |
160 | + out_fmt.dwChannelMask = KSAUDIO_SPEAKER_5POINT1_SURROUND; | |
161 | + break; | |
162 | + default: | |
163 | + out_fmt.dwChannelMask = 0; | |
164 | + } | |
165 | + } | |
166 | + | |
167 | + // Set sample rate | |
168 | + out_fmt.Format.nSamplesPerSec = sample_rate; | |
169 | + | |
170 | + // Block align | |
171 | + const unsigned align = channels * bytes_per_sample; | |
172 | + const unsigned bytes_per_sec = align * sample_rate; | |
173 | + out_fmt.Format.nBlockAlign = align; | |
174 | + | |
175 | + out_fmt.Format.nAvgBytesPerSec = bytes_per_sec; | |
176 | + | |
177 | + // Set bits per sample | |
178 | + out_fmt.Format.wBitsPerSample = bytes_per_sample << 3; | |
179 | +} | |
177 | 180 | |
178 | 181 | /////////////////////////////////////////////////////////////////////////////// |
@@ -17,6 +17,7 @@ | ||
17 | 17 | #include <mmsystem.h> |
18 | 18 | #include <dsound.h> |
19 | 19 | #include <objbase.h> |
20 | +#include <mmreg.h> // For WAVEFORMATEXTENSIBLE | |
20 | 21 | |
21 | 22 | /////////////////////////////////////////////////////////////////////////////// |
22 | 23 |
@@ -36,6 +37,11 @@ public: | ||
36 | 37 | |
37 | 38 | void play(bool loop); |
38 | 39 | void stop(); |
40 | + | |
41 | + static void CreateWaveFormat(unsigned sample_rate, | |
42 | + unsigned channels, | |
43 | + enum Cin_Format format, | |
44 | + WAVEFORMATEXTENSIBLE &out_fmt); | |
39 | 45 | }; |
40 | 46 | |
41 | 47 | /////////////////////////////////////////////////////////////////////////////// |