libOggFLAC.m4: Remove libOggFLAC.m4 as it's buggy.
[mpd-mk.git] / src / pcm_volume.c
blob240c779d844036fcbbaf4804060f7b8ff2eadabd
1 /*
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.
20 #include "config.h"
21 #include "pcm_volume.h"
22 #include "pcm_utils.h"
23 #include "audio_format.h"
25 #include <glib.h>
27 #include <stdint.h>
28 #include <string.h>
30 #undef G_LOG_DOMAIN
31 #define G_LOG_DOMAIN "pcm_volume"
33 static void
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() +
40 PCM_VOLUME_1 / 2)
41 / PCM_VOLUME_1;
43 *buffer++ = pcm_range(sample, 8);
44 --num_samples;
48 static void
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() +
55 PCM_VOLUME_1 / 2)
56 / PCM_VOLUME_1;
58 *buffer++ = pcm_range(sample, 16);
59 --num_samples;
63 #ifdef __i386__
64 /**
65 * Optimized volume function for i386. Use the EDX:EAX 2*32 bit
66 * multiplication result instead of emulating 64 bit multiplication.
68 static inline int32_t
69 pcm_volume_sample_24(int32_t sample, int32_t volume, G_GNUC_UNUSED int32_t dither)
71 int32_t result;
73 asm(/* edx:eax = sample * volume */
74 "imul %2\n"
76 /* "add %3, %1\n" dithering disabled for now, because we
77 have no overflow check - is dithering really important
78 here? */
80 /* eax = edx:eax / PCM_VOLUME_1 */
81 "sal $22, %%edx\n"
82 "shr $10, %1\n"
83 "or %%edx, %1\n"
85 : "=a"(result)
86 : "0"(sample), "r"(volume) /* , "r"(dither) */
87 : "edx"
90 return result;
92 #endif
94 static void
95 pcm_volume_change_24(int32_t *buffer, unsigned num_samples, int volume)
97 while (num_samples > 0) {
98 #ifdef __i386__
99 /* assembly version for i386 */
100 int32_t sample = *buffer;
102 sample = pcm_volume_sample_24(sample, volume,
103 pcm_volume_dither());
104 #else
105 /* portable version */
106 int64_t sample = *buffer;
108 sample = (sample * volume + pcm_volume_dither() +
109 PCM_VOLUME_1 / 2)
110 / PCM_VOLUME_1;
111 #endif
112 *buffer++ = pcm_range(sample, 24);
113 --num_samples;
117 static void
118 pcm_volume_change_32(int32_t *buffer, unsigned num_samples, int volume)
120 while (num_samples > 0) {
121 #ifdef __i386__
122 /* assembly version for i386 */
123 int32_t sample = *buffer;
125 *buffer++ = pcm_volume_sample_24(sample, volume, 0);
126 #else
127 /* portable version */
128 int64_t sample = *buffer;
130 sample = (sample * volume + pcm_volume_dither() +
131 PCM_VOLUME_1 / 2)
132 / PCM_VOLUME_1;
133 *buffer++ = pcm_range_64(sample, 32);
134 #endif
136 --num_samples;
140 bool
141 pcm_volume(void *buffer, int length,
142 const struct audio_format *format,
143 int volume)
145 if (volume == PCM_VOLUME_1)
146 return true;
148 if (volume <= 0) {
149 memset(buffer, 0, length);
150 return true;
153 switch (format->format) {
154 case SAMPLE_FORMAT_S8:
155 pcm_volume_change_8((int8_t *)buffer, length, volume);
156 return true;
158 case SAMPLE_FORMAT_S16:
159 pcm_volume_change_16((int16_t *)buffer, length / 2,
160 volume);
161 return true;
163 case SAMPLE_FORMAT_S24_P32:
164 pcm_volume_change_24((int32_t*)buffer, length / 4,
165 volume);
166 return true;
168 case SAMPLE_FORMAT_S32:
169 pcm_volume_change_32((int32_t*)buffer, length / 4,
170 volume);
171 return true;
173 default:
174 return false;