1 /* GStreamer
2  * Copyright (C) 2010 Mark Nauwelaerts <mark.nauwelaerts@collabora.co.uk>
3  * Copyright (C) 2010 Nokia Corporation. All rights reserved.
4  *   Contact: Stefan Kost <stefan.kost@nokia.com>
5  *
6  * Tremor modifications <2006>:
7  *   Chris Lord, OpenedHand Ltd. <chris@openedhand.com>, http://www.o-hand.com/
8  *
9  * This library is free software; you can redistribute it and/or
10  * modify it under the terms of the GNU Library General Public
11  * License as published by the Free Software Foundation; either
12  * version 2 of the License, or (at your option) any later version.
13  *
14  * This library is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
17  * Library General Public License for more details.
18  *
19  * You should have received a copy of the GNU Library General Public
20  * License along with this library; if not, write to the
21  * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
22  * Boston, MA 02110-1301, USA.
23  */
24 
25 #ifdef HAVE_CONFIG_H
26 #include "config.h"
27 #endif
28 
29 #include <string.h>
30 #include "gstvorbisdeclib.h"
31 #include "gstvorbiscommon.h"
32 
33 #ifndef TREMOR
34 /* These samples can be outside of the float -1.0 -- 1.0 range, this
35  * is allowed, downstream elements are supposed to clip */
36 static void
copy_samples_m(vorbis_sample_t * out,vorbis_sample_t ** in,guint samples,gint channels)37 copy_samples_m (vorbis_sample_t * out, vorbis_sample_t ** in, guint samples,
38     gint channels)
39 {
40   memcpy (out, in[0], samples * sizeof (float));
41 }
42 
43 static void
copy_samples_s(vorbis_sample_t * out,vorbis_sample_t ** in,guint samples,gint channels)44 copy_samples_s (vorbis_sample_t * out, vorbis_sample_t ** in, guint samples,
45     gint channels)
46 {
47 #ifdef GST_VORBIS_DEC_SEQUENTIAL
48   memcpy (out, in[0], samples * sizeof (float));
49   out += samples;
50   memcpy (out, in[1], samples * sizeof (float));
51 #else
52   gint j;
53 
54   for (j = 0; j < samples; j++) {
55     *out++ = in[0][j];
56     *out++ = in[1][j];
57   }
58 #endif
59 }
60 
61 static void
copy_samples(vorbis_sample_t * out,vorbis_sample_t ** in,guint samples,gint channels)62 copy_samples (vorbis_sample_t * out, vorbis_sample_t ** in, guint samples,
63     gint channels)
64 {
65 #ifdef GST_VORBIS_DEC_SEQUENTIAL
66   gint i;
67 
68   for (i = 0; i < channels; i++) {
69     memcpy (out, in[gst_vorbis_reorder_map[channels - 1][i]],
70         samples * sizeof (float));
71     out += samples;
72   }
73 #else
74   gint i, j;
75 
76   for (j = 0; j < samples; j++) {
77     for (i = 0; i < channels; i++) {
78       *out++ = in[gst_vorbis_reorder_map[channels - 1][i]][j];
79     }
80   }
81 #endif
82 }
83 
84 static void
copy_samples_no_reorder(vorbis_sample_t * out,vorbis_sample_t ** in,guint samples,gint channels)85 copy_samples_no_reorder (vorbis_sample_t * out, vorbis_sample_t ** in,
86     guint samples, gint channels)
87 {
88 #ifdef GST_VORBIS_DEC_SEQUENTIAL
89   gint i;
90 
91   for (i = 0; i < channels; i++) {
92     memcpy (out, in[i], samples * sizeof (float));
93     out += samples;
94   }
95 #else
96   gint i, j;
97 
98   for (j = 0; j < samples; j++) {
99     for (i = 0; i < channels; i++) {
100       *out++ = in[i][j];
101     }
102   }
103 #endif
104 }
105 
106 CopySampleFunc
gst_vorbis_get_copy_sample_func(gint channels)107 gst_vorbis_get_copy_sample_func (gint channels)
108 {
109   CopySampleFunc f = NULL;
110 
111   switch (channels) {
112     case 1:
113       f = copy_samples_m;
114       break;
115     case 2:
116       f = copy_samples_s;
117       break;
118     case 3:
119     case 4:
120     case 5:
121     case 6:
122     case 7:
123     case 8:
124       f = copy_samples;
125       break;
126     default:
127       f = copy_samples_no_reorder;
128       break;
129   }
130 
131   return f;
132 }
133 
134 #else
135 
136 /* Taken from Tremor, misc.h */
137 #ifdef _ARM_ASSEM_
138 static inline ogg_int32_t
CLIP_TO_15(ogg_int32_t x)139 CLIP_TO_15 (ogg_int32_t x)
140 {
141   int tmp;
142   asm volatile ("subs	%1, %0, #32768\n\t"
143       "movpl	%0, #0x7f00\n\t"
144       "orrpl	%0, %0, #0xff\n"
145       "adds	%1, %0, #32768\n\t"
146       "movmi	%0, #0x8000":"+r" (x), "=r" (tmp)
147       ::"cc");
148 
149   return (x);
150 }
151 #else
152 static inline ogg_int32_t
CLIP_TO_15(ogg_int32_t x)153 CLIP_TO_15 (ogg_int32_t x)
154 {
155   int ret = x;
156 
157   ret -= ((x <= 32767) - 1) & (x - 32767);
158   ret -= ((x >= -32768) - 1) & (x + 32768);
159   return (ret);
160 }
161 #endif
162 
163 static void
copy_samples_16_m(vorbis_sample_t * _out,vorbis_sample_t ** _in,guint samples,gint channels)164 copy_samples_16_m (vorbis_sample_t * _out, vorbis_sample_t ** _in,
165     guint samples, gint channels)
166 {
167   gint16 *out = (gint16 *) _out;
168   ogg_int32_t **in = (ogg_int32_t **) _in;
169   gint j;
170 
171   for (j = 0; j < samples; j++) {
172     *out++ = CLIP_TO_15 (in[0][j] >> 9);
173   }
174 }
175 
176 static void
copy_samples_16_s(vorbis_sample_t * _out,vorbis_sample_t ** _in,guint samples,gint channels)177 copy_samples_16_s (vorbis_sample_t * _out, vorbis_sample_t ** _in,
178     guint samples, gint channels)
179 {
180   gint16 *out = (gint16 *) _out;
181   ogg_int32_t **in = (ogg_int32_t **) _in;
182   gint j;
183 
184   for (j = 0; j < samples; j++) {
185     *out++ = CLIP_TO_15 (in[0][j] >> 9);
186     *out++ = CLIP_TO_15 (in[1][j] >> 9);
187   }
188 }
189 
190 static void
copy_samples_16(vorbis_sample_t * _out,vorbis_sample_t ** _in,guint samples,gint channels)191 copy_samples_16 (vorbis_sample_t * _out, vorbis_sample_t ** _in, guint samples,
192     gint channels)
193 {
194   gint16 *out = (gint16 *) _out;
195   ogg_int32_t **in = (ogg_int32_t **) _in;
196   gint i, j;
197 
198   for (j = 0; j < samples; j++) {
199     for (i = 0; i < channels; i++) {
200       *out++ = CLIP_TO_15 (in[gst_vorbis_reorder_map[channels - 1][i]][j] >> 9);
201     }
202   }
203 }
204 
205 CopySampleFunc
gst_vorbis_get_copy_sample_func(gint channels)206 gst_vorbis_get_copy_sample_func (gint channels)
207 {
208   CopySampleFunc f = NULL;
209 
210   switch (channels) {
211     case 1:
212       f = copy_samples_16_m;
213       break;
214     case 2:
215       f = copy_samples_16_s;
216       break;
217     default:
218       f = copy_samples_16;
219       break;
220   }
221   return f;
222 }
223 
224 #endif
225