diff options
Diffstat (limited to 'apps/codecs/libpcm/linear_pcm.c')
-rw-r--r-- | apps/codecs/libpcm/linear_pcm.c | 163 |
1 files changed, 163 insertions, 0 deletions
diff --git a/apps/codecs/libpcm/linear_pcm.c b/apps/codecs/libpcm/linear_pcm.c new file mode 100644 index 0000000000..2c766bd741 --- /dev/null +++ b/apps/codecs/libpcm/linear_pcm.c | |||
@@ -0,0 +1,163 @@ | |||
1 | /*************************************************************************** | ||
2 | * __________ __ ___. | ||
3 | * Open \______ \ ____ ____ | | _\_ |__ _______ ___ | ||
4 | * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ / | ||
5 | * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < < | ||
6 | * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \ | ||
7 | * \/ \/ \/ \/ \/ | ||
8 | * $Id$ | ||
9 | * | ||
10 | * Copyright (C) 2005 Dave Chapman | ||
11 | * Copyright (C) 2009 Yoshihisa Uchida | ||
12 | * | ||
13 | * This program is free software; you can redistribute it and/or | ||
14 | * modify it under the terms of the GNU General Public License | ||
15 | * as published by the Free Software Foundation; either version 2 | ||
16 | * of the License, or (at your option) any later version. | ||
17 | * | ||
18 | * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY | ||
19 | * KIND, either express or implied. | ||
20 | * | ||
21 | ****************************************************************************/ | ||
22 | #include "codeclib.h" | ||
23 | #include "pcm_common.h" | ||
24 | |||
25 | /* | ||
26 | * Linear PCM | ||
27 | */ | ||
28 | |||
29 | static struct pcm_format *fmt; | ||
30 | |||
31 | static bool set_format(struct pcm_format *format, const unsigned char *fmtpos) | ||
32 | { | ||
33 | fmt = format; | ||
34 | |||
35 | (void)fmtpos; | ||
36 | |||
37 | if (fmt->bitspersample > 32) | ||
38 | { | ||
39 | DEBUGF("CODEC_ERROR: pcm with more than 32 bitspersample " | ||
40 | "is unsupported\n"); | ||
41 | return false; | ||
42 | } | ||
43 | |||
44 | if (fmt->totalsamples == 0) | ||
45 | { | ||
46 | fmt->bytespersample = (((fmt->bitspersample - 1)/8 + 1)*fmt->channels); | ||
47 | fmt->totalsamples = fmt->numbytes/fmt->bytespersample; | ||
48 | } | ||
49 | |||
50 | /* chunksize is computed so that one chunk is about 1/50s. | ||
51 | * this make 4096 for 44.1kHz 16bits stereo. | ||
52 | * It also has to be a multiple of blockalign */ | ||
53 | fmt->chunksize = (1 + fmt->avgbytespersec / (50*fmt->blockalign))*fmt->blockalign; | ||
54 | |||
55 | return true; | ||
56 | } | ||
57 | |||
58 | static uint32_t get_seek_pos(long seek_time) | ||
59 | { | ||
60 | uint32_t newpos; | ||
61 | |||
62 | /* use avgbytespersec to round to the closest blockalign multiple, | ||
63 | add firstblockposn. 64-bit casts to avoid overflows. */ | ||
64 | newpos = (((uint64_t)fmt->avgbytespersec*(seek_time - 1)) | ||
65 | / (1000LL*fmt->blockalign))*fmt->blockalign; | ||
66 | return newpos; | ||
67 | } | ||
68 | |||
69 | static int decode(const uint8_t *inbuf, size_t inbufsize, | ||
70 | int32_t *outbuf, int *outbufsize) | ||
71 | { | ||
72 | uint32_t i; | ||
73 | |||
74 | if (fmt->bitspersample > 24) | ||
75 | { | ||
76 | for (i = 0; i < inbufsize; i += 4) | ||
77 | { | ||
78 | if (fmt->is_little_endian) | ||
79 | { | ||
80 | if (fmt->is_signed) | ||
81 | outbuf[i/4] = (inbuf[i]>>3)|(inbuf[i+1]<<5)|(inbuf[i+2]<<13)|(SE(inbuf[i+3])<<21); | ||
82 | else | ||
83 | outbuf[i/4] = (inbuf[i]>>3)|(inbuf[i+1]<<5)|(inbuf[i+2]<<13)|(SFT(inbuf[i+3])<<21); | ||
84 | } | ||
85 | else | ||
86 | { | ||
87 | if (fmt->is_signed) | ||
88 | outbuf[i/4] = (inbuf[i+3]>>3)|(inbuf[i+2]<<5)|(inbuf[i+1]<<13)|(SE(inbuf[i])<<21); | ||
89 | else | ||
90 | outbuf[i/4] = (inbuf[i+3]>>3)|(inbuf[i+2]<<5)|(inbuf[i+1]<<13)|(SFT(inbuf[i])<<21); | ||
91 | } | ||
92 | } | ||
93 | *outbufsize = inbufsize >> 2; | ||
94 | } | ||
95 | else if (fmt->bitspersample > 16) | ||
96 | { | ||
97 | for (i = 0; i < inbufsize; i += 3) | ||
98 | { | ||
99 | if (fmt->is_little_endian) | ||
100 | { | ||
101 | if (fmt->is_signed) | ||
102 | outbuf[i/3] = (inbuf[i]<<5)|(inbuf[i+1]<<13)|(SE(inbuf[i+2])<<21); | ||
103 | else | ||
104 | outbuf[i/3] = (inbuf[i]<<5)|(inbuf[i+1]<<13)|(SFT(inbuf[i+2])<<21); | ||
105 | } | ||
106 | else | ||
107 | { | ||
108 | if (fmt->is_signed) | ||
109 | outbuf[i/3] = (inbuf[i+2]<<5)|(inbuf[i+1]<<13)|(SE(inbuf[i])<<21); | ||
110 | else | ||
111 | outbuf[i/3] = (inbuf[i+2]<<5)|(inbuf[i+1]<<13)|(SFT(inbuf[i])<<21); | ||
112 | } | ||
113 | } | ||
114 | *outbufsize = inbufsize/3; | ||
115 | } | ||
116 | else if (fmt->bitspersample > 8) | ||
117 | { | ||
118 | for (i = 0; i < inbufsize; i += 2) | ||
119 | { | ||
120 | if (fmt->is_little_endian) | ||
121 | { | ||
122 | if (fmt->is_signed) | ||
123 | outbuf[i/2] = (inbuf[i]<<13)|(SE(inbuf[i+1])<<21); | ||
124 | else | ||
125 | outbuf[i/2] = (inbuf[i]<<13)|(SFT(inbuf[i+1])<<21); | ||
126 | } | ||
127 | else | ||
128 | { | ||
129 | if (fmt->is_signed) | ||
130 | outbuf[i/2] = (inbuf[i+1]<<13)|(SE(inbuf[i])<<21); | ||
131 | else | ||
132 | outbuf[i/2] = (inbuf[i+1]<<13)|(SFT(inbuf[i])<<21); | ||
133 | } | ||
134 | } | ||
135 | *outbufsize = inbufsize >> 1; | ||
136 | } | ||
137 | else | ||
138 | { | ||
139 | for (i = 0; i < inbufsize; i++) { | ||
140 | if (fmt->is_signed) | ||
141 | outbuf[i] = SE(inbuf[i])<<21; | ||
142 | else | ||
143 | outbuf[i] = SFT(inbuf[i])<<21; | ||
144 | } | ||
145 | *outbufsize = inbufsize; | ||
146 | } | ||
147 | |||
148 | if (fmt->channels == 2) | ||
149 | *outbufsize >>= 1; | ||
150 | |||
151 | return CODEC_OK; | ||
152 | } | ||
153 | |||
154 | static const struct pcm_codec codec = { | ||
155 | set_format, | ||
156 | get_seek_pos, | ||
157 | decode, | ||
158 | }; | ||
159 | |||
160 | const struct pcm_codec *get_linear_pcm_codec(void) | ||
161 | { | ||
162 | return &codec; | ||
163 | } | ||