2 * Copyright (C) 2003-2010 The Music Player Daemon Project
3 * http://www.musicpd.org
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License along
16 * with this program; if not, write to the Free Software Foundation, Inc.,
17 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
21 #include "pcm_volume.h"
22 #include "pcm_utils.h"
23 #include "audio_format.h"
31 #define G_LOG_DOMAIN "pcm_volume"
34 pcm_volume_change_8(int8_t *buffer
, unsigned num_samples
, int volume
)
36 while (num_samples
> 0) {
37 int32_t sample
= *buffer
;
39 sample
= (sample
* volume
+ pcm_volume_dither() +
43 *buffer
++ = pcm_range(sample
, 8);
49 pcm_volume_change_16(int16_t *buffer
, unsigned num_samples
, int volume
)
51 while (num_samples
> 0) {
52 int32_t sample
= *buffer
;
54 sample
= (sample
* volume
+ pcm_volume_dither() +
58 *buffer
++ = pcm_range(sample
, 16);
65 * Optimized volume function for i386. Use the EDX:EAX 2*32 bit
66 * multiplication result instead of emulating 64 bit multiplication.
69 pcm_volume_sample_24(int32_t sample
, int32_t volume
, G_GNUC_UNUSED
int32_t dither
)
73 asm(/* edx:eax = sample * volume */
76 /* "add %3, %1\n" dithering disabled for now, because we
77 have no overflow check - is dithering really important
80 /* eax = edx:eax / PCM_VOLUME_1 */
86 : "0"(sample
), "r"(volume
) /* , "r"(dither) */
95 pcm_volume_change_24(int32_t *buffer
, unsigned num_samples
, int volume
)
97 while (num_samples
> 0) {
99 /* assembly version for i386 */
100 int32_t sample
= *buffer
;
102 sample
= pcm_volume_sample_24(sample
, volume
,
103 pcm_volume_dither());
105 /* portable version */
106 int64_t sample
= *buffer
;
108 sample
= (sample
* volume
+ pcm_volume_dither() +
112 *buffer
++ = pcm_range(sample
, 24);
118 pcm_volume_change_32(int32_t *buffer
, unsigned num_samples
, int volume
)
120 while (num_samples
> 0) {
122 /* assembly version for i386 */
123 int32_t sample
= *buffer
;
125 *buffer
++ = pcm_volume_sample_24(sample
, volume
, 0);
127 /* portable version */
128 int64_t sample
= *buffer
;
130 sample
= (sample
* volume
+ pcm_volume_dither() +
133 *buffer
++ = pcm_range_64(sample
, 32);
141 pcm_volume(void *buffer
, int length
,
142 const struct audio_format
*format
,
145 if (volume
== PCM_VOLUME_1
)
149 memset(buffer
, 0, length
);
153 switch (format
->format
) {
154 case SAMPLE_FORMAT_S8
:
155 pcm_volume_change_8((int8_t *)buffer
, length
, volume
);
158 case SAMPLE_FORMAT_S16
:
159 pcm_volume_change_16((int16_t *)buffer
, length
/ 2,
163 case SAMPLE_FORMAT_S24_P32
:
164 pcm_volume_change_24((int32_t*)buffer
, length
/ 4,
168 case SAMPLE_FORMAT_S32
:
169 pcm_volume_change_32((int32_t*)buffer
, length
/ 4,