リビジョン | 097ceffeb1c2133af6e2d060b22e1457035be75a (tree) |
---|---|
日時 | 2020-01-05 08:27:38 |
作者 | AlaskanEmily <emily@alas...> |
コミッター | AlaskanEmily |
Add per-sound volume on Cin_Sound
@@ -127,6 +127,31 @@ CIN_EXPORT(enum Cin_SoundError) Cin_SoundPlayLoop(struct Cin_Sound *snd, | ||
127 | 127 | |
128 | 128 | CIN_EXPORT(enum Cin_SoundError) Cin_SoundStop(struct Cin_Sound *snd); |
129 | 129 | |
130 | +/** | |
131 | + * @brief Sets the volume of the sound. | |
132 | + * | |
133 | + * The range is from 0-255. | |
134 | + * | |
135 | + * @sa Cin_SoundGetVolume | |
136 | + */ | |
137 | +CIN_EXPORT(enum Cin_SoundError) Cin_SoundSetVolume(struct Cin_Sound *snd, | |
138 | + unsigned char volume); | |
139 | + | |
140 | +/** | |
141 | + * @brief Gets the volume of the sound. | |
142 | + * | |
143 | + * It is guaranteed that after a successful call to Cin_SoundSetVolume this | |
144 | + * function will output the same value as was passed when setting the volume. | |
145 | + * | |
146 | + * On failure, this will not modify @p out_volume. | |
147 | + * | |
148 | + * The range is from 0-255. | |
149 | + * | |
150 | + * @sa Cin_SoundSetVolume | |
151 | + */ | |
152 | +CIN_EXPORT(enum Cin_SoundError) Cin_SoundGetVolume(const struct Cin_Sound *snd, | |
153 | + unsigned char *out_volume); | |
154 | + | |
130 | 155 | CIN_EXPORT(void) Cin_DestroySound(struct Cin_Sound *snd); |
131 | 156 | |
132 | 157 | /** @} */ /* End Sound group. */ |
@@ -8,6 +8,7 @@ | ||
8 | 8 | #include "cin_soft_loader.h" |
9 | 9 | #include "cinnamon.h" |
10 | 10 | |
11 | +#include <assert.h> | |
11 | 12 | #include <new> |
12 | 13 | |
13 | 14 | /////////////////////////////////////////////////////////////////////////////// |
@@ -143,6 +144,36 @@ CIN_EXPORT(enum Cin_SoundError) Cin_SoundStop(Cin_Sound *snd){ | ||
143 | 144 | |
144 | 145 | /////////////////////////////////////////////////////////////////////////////// |
145 | 146 | |
147 | +CIN_EXPORT(enum Cin_SoundError) Cin_SoundSetVolume(struct Cin_Sound *snd, | |
148 | + unsigned char volume){ | |
149 | + | |
150 | + assert(snd != NULL); | |
151 | + if(snd->setVolume(volume)) | |
152 | + return Cin_eSoundSuccess; | |
153 | + else | |
154 | + return Cin_eSoundFailure; | |
155 | +} | |
156 | + | |
157 | +/////////////////////////////////////////////////////////////////////////////// | |
158 | + | |
159 | +CIN_EXPORT(enum Cin_SoundError) Cin_SoundGetVolume(const struct Cin_Sound *snd, | |
160 | + unsigned char *out_volume){ | |
161 | + | |
162 | + assert(snd != NULL); | |
163 | + assert(out_volume != NULL); | |
164 | + | |
165 | + unsigned char volume; | |
166 | + if(snd->getVolume(volume)){ | |
167 | + out_volume[0] = volume; | |
168 | + return Cin_eSoundSuccess; | |
169 | + } | |
170 | + else{ | |
171 | + return Cin_eSoundFailure; | |
172 | + } | |
173 | +} | |
174 | + | |
175 | +/////////////////////////////////////////////////////////////////////////////// | |
176 | + | |
146 | 177 | CIN_EXPORT(void) Cin_DestroySound(Cin_Sound *snd){ |
147 | 178 | snd->~Cin_Sound(); |
148 | 179 | } |
@@ -87,6 +87,34 @@ void Cin_Sound::stop(){ | ||
87 | 87 | if(m_buffer != NULL) |
88 | 88 | m_buffer->Stop(); |
89 | 89 | } |
90 | + | |
91 | +/////////////////////////////////////////////////////////////////////////////// | |
92 | + | |
93 | +bool Cin_Sound::setVolume(const unsigned char volume){ | |
94 | + const LONG vol = MulDiv(volume, DSBVOLUME_MAX - DSBVOLUME_MIN, 255); | |
95 | + const LONG long_vol = vol + DSBVOLUME_MIN; | |
96 | + | |
97 | + return m_buffer && SUCCEEDED(m_buffer->SetVolume(long_vol)); | |
98 | +} | |
99 | + | |
100 | +/////////////////////////////////////////////////////////////////////////////// | |
101 | + | |
102 | +bool Cin_Sound::getVolume(unsigned char &out_volume) const{ | |
103 | + LONG long_vol; | |
104 | + if(m_buffer == NULL || FAILED(m_buffer->GetVolume(&long_vol))) | |
105 | + return false; | |
106 | + | |
107 | + long_vol -= DSBVOLUME_MIN; | |
108 | + const LONG vol = MulDiv(long_vol, 255, DSBVOLUME_MAX - DSBVOLUME_MIN); | |
109 | + | |
110 | + assert(vol > 0); | |
111 | + assert(vol < 0x100); | |
112 | + | |
113 | + out_volume = static_cast<unsigned char>(vol); | |
114 | + | |
115 | + return true; | |
116 | +} | |
117 | + | |
90 | 118 | /////////////////////////////////////////////////////////////////////////////// |
91 | 119 | |
92 | 120 | void Cin_Sound::CreateWaveFormat(unsigned sample_rate, |
@@ -38,6 +38,9 @@ public: | ||
38 | 38 | void play(bool loop); |
39 | 39 | void stop(); |
40 | 40 | |
41 | + bool setVolume(unsigned char volume); | |
42 | + bool getVolume(unsigned char &out_volume) const; | |
43 | + | |
41 | 44 | static void CreateWaveFormat(unsigned sample_rate, |
42 | 45 | unsigned channels, |
43 | 46 | enum Cin_Format format, |
@@ -12,6 +12,75 @@ | ||
12 | 12 | #include <assert.h> |
13 | 13 | |
14 | 14 | /*****************************************************************************/ |
15 | +/* See gen_float_table.py for how this table was generated. */ | |
16 | +static const float char_to_float_table[0x100] = { | |
17 | + 0.0000000000f, 0.0000000000f, 0.0000000000f, 0.0000000000f, | |
18 | + 0.0000000000f, 0.0000000000f, 0.0000000000f, 0.0000000000f, | |
19 | + 0.0000000000f, 0.0000000000f, 0.0000000000f, 0.0000000000f, | |
20 | + 0.0000000000f, 0.0000000000f, 0.0000000000f, 0.0000000000f, | |
21 | + 0.0000000000f, 0.0094771457f, 0.0186795915f, 0.0276100044f, | |
22 | + 0.0362710514f, 0.0446653996f, 0.0527957157f, 0.0606646670f, | |
23 | + 0.0682749203f, 0.0756291427f, 0.0827300011f, 0.0895801626f, | |
24 | + 0.0961822940f, 0.1025390625f, 0.1086531350f, 0.1145271784f, | |
25 | + 0.1201638598f, 0.1255658462f, 0.1307358045f, 0.1356764018f, | |
26 | + 0.1403903050f, 0.1448801811f, 0.1491486971f, 0.1531985200f, | |
27 | + 0.1570323168f, 0.1606527545f, 0.1640625000f, 0.1672642204f, | |
28 | + 0.1702605826f, 0.1730542537f, 0.1756479005f, 0.1780441902f, | |
29 | + 0.1802457897f, 0.1822553660f, 0.1840755860f, 0.1857091168f, | |
30 | + 0.1871586254f, 0.1884267787f, 0.1895162437f, 0.1904296875f, | |
31 | + 0.1911697770f, 0.1917391791f, 0.1921405610f, 0.1923765895f, | |
32 | + 0.1924499317f, 0.1923632546f, 0.1921192251f, 0.1917205102f, | |
33 | + 0.1911697770f, 0.1904696923f, 0.1896229233f, 0.1886321369f, | |
34 | + 0.1875000000f, 0.1862291797f, 0.1848223430f, 0.1832821568f, | |
35 | + 0.1816112881f, 0.1798124040f, 0.1778881714f, 0.1758412573f, | |
36 | + 0.1736743286f, 0.1713900525f, 0.1689910958f, 0.1664801256f, | |
37 | + 0.1638598088f, 0.1611328125f, 0.1583018036f, 0.1553694491f, | |
38 | + 0.1523384160f, 0.1492113713f, 0.1459909820f, 0.1426799151f, | |
39 | + 0.1392808375f, 0.1357964163f, 0.1322293184f, 0.1285822108f, | |
40 | + 0.1248577606f, 0.1210586346f, 0.1171875000f, 0.1132470236f, | |
41 | + 0.1092398726f, 0.1051687137f, 0.1010362142f, 0.0968450408f, | |
42 | + 0.0925978607f, 0.0882973408f, 0.0839461482f, 0.0795469497f, | |
43 | + 0.0751024124f, 0.0706152033f, 0.0660879893f, 0.0615234375f, | |
44 | + 0.0569242148f, 0.0522929883f, 0.0476324249f, 0.0429451916f, | |
45 | + 0.0382339554f, 0.0335013833f, 0.0287501422f, 0.0239828993f, | |
46 | + 0.0192023213f, 0.0144110755f, 0.0096118286f, 0.0048072478f, | |
47 | + 0.5000000000f, 0.5000000000f, 0.5000000000f, 0.5000000000f, | |
48 | + 0.5000000000f, 0.5000000000f, 0.5000000000f, 0.5000000000f, | |
49 | + 0.5000000000f, 0.5000000000f, 0.5000000000f, 0.5000000000f, | |
50 | + 0.5000000000f, 0.5000000000f, 0.5000000000f, 0.5000000000f, | |
51 | + 0.5000000000f, 0.5094771457f, 0.5186795915f, 0.5276100044f, | |
52 | + 0.5362710514f, 0.5446653996f, 0.5527957157f, 0.5606646670f, | |
53 | + 0.5682749203f, 0.5756291427f, 0.5827300011f, 0.5895801626f, | |
54 | + 0.5961822940f, 0.6025390625f, 0.6086531350f, 0.6145271784f, | |
55 | + 0.6201638598f, 0.6255658462f, 0.6307358045f, 0.6356764018f, | |
56 | + 0.6403903050f, 0.6448801811f, 0.6491486971f, 0.6531985200f, | |
57 | + 0.6570323168f, 0.6606527545f, 0.6640625000f, 0.6672642204f, | |
58 | + 0.6702605826f, 0.6730542537f, 0.6756479005f, 0.6780441902f, | |
59 | + 0.6802457897f, 0.6822553660f, 0.6840755860f, 0.6857091168f, | |
60 | + 0.6871586254f, 0.6884267787f, 0.6895162437f, 0.6904296875f, | |
61 | + 0.6911697770f, 0.6917391791f, 0.6921405610f, 0.6923765895f, | |
62 | + 0.6924499317f, 0.6923632546f, 0.6921192251f, 0.6917205102f, | |
63 | + 0.6911697770f, 0.6904696923f, 0.6896229233f, 0.6886321369f, | |
64 | + 0.6875000000f, 0.6862291797f, 0.6848223430f, 0.6832821568f, | |
65 | + 0.6816112881f, 0.6798124040f, 0.6778881714f, 0.6758412573f, | |
66 | + 0.6736743286f, 0.6713900525f, 0.6689910958f, 0.6664801256f, | |
67 | + 0.6638598088f, 0.6611328125f, 0.6583018036f, 0.6553694491f, | |
68 | + 0.6523384160f, 0.6492113713f, 0.6459909820f, 0.6426799151f, | |
69 | + 0.6392808375f, 0.6357964163f, 0.6322293184f, 0.6285822108f, | |
70 | + 0.6248577606f, 0.6210586346f, 0.6171875000f, 0.6132470236f, | |
71 | + 0.6092398726f, 0.6051687137f, 0.6010362142f, 0.5968450408f, | |
72 | + 0.5925978607f, 0.5882973408f, 0.5839461482f, 0.5795469497f, | |
73 | + 0.5751024124f, 0.5706152033f, 0.5660879893f, 0.5615234375f, | |
74 | + 0.5569242148f, 0.5522929883f, 0.5476324249f, 0.5429451916f, | |
75 | + 0.5382339554f, 0.5335013833f, 0.5287501422f, 0.5239828993f, | |
76 | + 0.5192023213f, 0.5144110755f, 0.5096118286f, 0.5048072478f, | |
77 | + 1.0000000000f, 1.0000000000f, 1.0000000000f, 1.0000000000f, | |
78 | + 1.0000000000f, 1.0000000000f, 1.0000000000f, 1.0000000000f, | |
79 | + 1.0000000000f, 1.0000000000f, 1.0000000000f, 1.0000000000f, | |
80 | + 1.0000000000f, 1.0000000000f, 1.0000000000f, 1.0000000000f | |
81 | +}; | |
82 | + | |
83 | +/*****************************************************************************/ | |
15 | 84 | |
16 | 85 | CIN_PRIVATE_PURE(ALuint) |
17 | 86 | Cin_CinFormatToOpenALFormat(enum Cin_Format f, unsigned num_channels){ |
@@ -334,6 +403,7 @@ enum Cin_LoaderError Cin_LoaderFinalize(struct Cin_Loader *ld, | ||
334 | 403 | |
335 | 404 | out->snd = ld->snd.snd; |
336 | 405 | out->ctx = ld->snd.ctx; |
406 | + out->volume = 0xFF; /* Default volume is 100% */ | |
337 | 407 | |
338 | 408 | ld->snd.snd = 0; |
339 | 409 | return Cin_eLoaderSuccess; |
@@ -374,6 +444,39 @@ enum Cin_SoundError Cin_SoundStop(struct Cin_Sound *snd){ | ||
374 | 444 | |
375 | 445 | /*****************************************************************************/ |
376 | 446 | |
447 | +CIN_EXPORT(enum Cin_SoundError) Cin_SoundSetVolume(struct Cin_Sound *snd, | |
448 | + unsigned char volume){ | |
449 | + | |
450 | + const float gain = char_to_float_table[volume]; | |
451 | + | |
452 | + assert(snd != NULL); | |
453 | + | |
454 | + /* Store the input volume as-is to be sure that calls to | |
455 | + * Cin_SoundSetVolume/Cin_SoundGetVolume are round-trip safe. | |
456 | + */ | |
457 | + snd->volume = volume; | |
458 | + | |
459 | + alSourcef(snd->snd, AL_GAIN, gain); | |
460 | + if(alGetError() != AL_NO_ERROR) | |
461 | + return Cin_eSoundFailure; | |
462 | + else | |
463 | + return Cin_eSoundSuccess; | |
464 | +} | |
465 | + | |
466 | +/*****************************************************************************/ | |
467 | + | |
468 | +CIN_EXPORT(enum Cin_SoundError) Cin_SoundGetVolume(const struct Cin_Sound *snd, | |
469 | + unsigned char *out_volume){ | |
470 | + | |
471 | + assert(snd != NULL); | |
472 | + assert(out_volume != NULL); | |
473 | + | |
474 | + out_volume[0] = snd->volume; | |
475 | + return Cin_eSoundSuccess; | |
476 | +} | |
477 | + | |
478 | +/*****************************************************************************/ | |
479 | + | |
377 | 480 | void Cin_DestroySound(struct Cin_Sound *snd){ |
378 | 481 | alcMakeContextCurrent(snd->ctx); |
379 | 482 | alDeleteSources(1, &(snd->snd)); |
@@ -104,6 +104,13 @@ struct Cin_Driver{ | ||
104 | 104 | struct Cin_Sound { |
105 | 105 | ALCcontext *ctx; |
106 | 106 | ALuint snd; |
107 | + /* The volume as set is separately stored here, since we use a one-way | |
108 | + * lookup table (of non-linear range no less!) for gain/volume setting. | |
109 | + * | |
110 | + * We want Cin_SoundSetVolume/Cin_SoundGetVolume to be round-trip | |
111 | + * idempotent, so we just store the volume here. | |
112 | + */ | |
113 | + unsigned char volume; | |
107 | 114 | }; |
108 | 115 | |
109 | 116 | /*****************************************************************************/ |
@@ -0,0 +1,95 @@ | ||
1 | +# Generates the C table of floats used translate from 0u-255u to 0.0f to 1.0f | |
2 | +# | |
3 | +# Copyright (C) 2020 AlaskanEmily | |
4 | +# | |
5 | +# This software is provided 'as-is', without any express or implied | |
6 | +# warranty. In no event will the authors be held liable for any damages | |
7 | +# arising from the use of this software. | |
8 | +# | |
9 | +# Permission is granted to anyone to use this software for any purpose, | |
10 | +# including commercial applications, and to alter it and redistribute it | |
11 | +# freely, subject to the following restrictions: | |
12 | +# | |
13 | +# - The origin of this software must not be misrepresented; you must not | |
14 | +# claim that you wrote the original software. If you use this software | |
15 | +# in a product, an acknowledgment in the product documentation would be | |
16 | +# appreciated but is not required. | |
17 | +# - Altered source versions must be plainly marked as such, and must not be | |
18 | +# misrepresented as being the original software. | |
19 | +# - This notice may not be removed or altered from any source distribution. | |
20 | +# | |
21 | + | |
22 | +LOW_SNAP = 16 | |
23 | +MID_SNAP0 = (128 - 8) | |
24 | +MID_SNAP1 = (128 + 8) | |
25 | +HI_SNAP = 240 | |
26 | + | |
27 | +LOW_LERP_TANGENT = 0.0 | |
28 | +MID_LERP_TANGENT = 1.0 | |
29 | +HIGH_LERP_TANGENT = 0.5 | |
30 | + | |
31 | +def CubicInterp(ValT, LoT, HiT, LoV, HiV): | |
32 | + # Convert T to 0.0-1.0 | |
33 | + T = float(ValT - LoT) / float(HiT - LoT) | |
34 | + A = (2.0 * pow(T, 3)) - (3.0 * pow(T, 2)) + 1.0 | |
35 | + B = pow(T, 3) - (2.0 * pow(T, 2)) + T | |
36 | + C = (-2.0 * pow(T, 3)) + (3.0 * pow(T, 2)) + 0.0 | |
37 | + D = pow(T, 3) - (2.0 * pow(T, 2)) | |
38 | + if LoT < 0.5: | |
39 | + Tan0 = LOW_LERP_TANGENT | |
40 | + Tan1 = MID_LERP_TANGENT | |
41 | + else: | |
42 | + Tan0 = MID_LERP_TANGENT | |
43 | + Tan1 = HIGH_LERP_TANGENT | |
44 | + | |
45 | + return (A * LoV) + (B * Tan0) + (C * HiV) + (D * Tan1) | |
46 | + | |
47 | +def Lerp(T, LoT, HiT, LoV, HiV): | |
48 | + return LoV + ((float(T - LoT) / float(HiT - LoT)) * (HiV - LoV)) | |
49 | + | |
50 | +def DoAppend(): | |
51 | + Line = " " | |
52 | + i = 0 | |
53 | + while True: | |
54 | + Value = (yield) | |
55 | + if Value == '\n': | |
56 | + i = 0 | |
57 | + else: | |
58 | + Str = "%1.10Ff, " % Value | |
59 | + Line += Str | |
60 | + i += 1 | |
61 | + | |
62 | + if i % 4 == 0: | |
63 | + print(Line) | |
64 | + Line = " " | |
65 | + | |
66 | +print("{") | |
67 | + | |
68 | +Append = DoAppend() | |
69 | +next(Append) | |
70 | + | |
71 | +e = 0 | |
72 | +while e < LOW_SNAP: | |
73 | + Append.send(0.0) | |
74 | + e += 1 | |
75 | + | |
76 | +while e < MID_SNAP0: | |
77 | + Value = CubicInterp(e, LOW_SNAP, MID_SNAP0, 0.0, 0.5) | |
78 | + Append.send(Value) | |
79 | + e += 1 | |
80 | + | |
81 | +while e < MID_SNAP1: | |
82 | + Append.send(0.5) | |
83 | + e += 1 | |
84 | + | |
85 | +while e < HI_SNAP: | |
86 | + Value = CubicInterp(e, MID_SNAP1, HI_SNAP, 0.5, 1.0) | |
87 | + Append.send(Value) | |
88 | + e += 1 | |
89 | + | |
90 | +while e <= 255: | |
91 | + Append.send(1.0) | |
92 | + e += 1 | |
93 | + | |
94 | +Append.send('\n') | |
95 | +print("};") |