├── README.md ├── c ├── freq_util │ ├── freq_util.c │ └── freq_util.h ├── kiss_fft │ ├── _kiss_fft_guts.h │ ├── kiss_fastfir.c │ ├── kiss_fastfir.h │ ├── kiss_fft.c │ ├── kiss_fft.h │ ├── kiss_fftr.c │ └── kiss_fftr.h └── rscode │ ├── rscode.c │ └── rscode.h ├── javascript ├── chirp.js └── example.html ├── objc └── PCMRender │ ├── PCMRender.h │ └── PCMRender.m └── php ├── rscode └── qrrscode.php └── wave └── WavForge.php /README.md: -------------------------------------------------------------------------------- 1 | WaveTransSdk (声波传输SDK) 2 | ============ 3 | 4 | [![paypaldonate](https://www.paypalobjects.com/en_GB/i/btn/btn_donate_SM.gif)](https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=VW7YCWNMQ7ZXY) 5 | 6 | ![](http://image.sinastorage.com/donate.png) 7 | 8 | 9 | c / 10 | - freq_util (频率管理) 11 | - kiss_fft (FFT) 12 | - rscode (Reed–Solomon error correction) 13 | 14 | javascript / 15 | - chirp.js (声音发送端的js的实现) 16 | - example.html (调用实例) 17 | 18 | php / 19 | - rscode (Reed–Solomon error correction PHP版本的实现) 20 | - wave (音频流生成器, PHP版本的实现) 21 | 22 | objc / 23 | - PCMRender (音频流生成器, Objective-C版本的实现) 24 | 25 | 26 | 27 | 28 | [![](http://service.t.sina.com.cn/widget/qmd/1656360925/02781ba4/4.png)](http://weibo.com/smcz) 29 | -------------------------------------------------------------------------------- /c/freq_util/freq_util.c: -------------------------------------------------------------------------------- 1 | 2 | #include "freq_util.h" 3 | 4 | 5 | 6 | 7 | static float frequencies[32] = BB_FREQUENCIES; 8 | static double theta = 0; 9 | 10 | 11 | void freq_init() { 12 | 13 | static int flag = 0; 14 | 15 | if (flag) { 16 | 17 | return; 18 | } 19 | 20 | 21 | #if 1 22 | 23 | printf("----------------------\n"); 24 | 25 | int i, len; 26 | 27 | for (i=0, len = strlen(BB_CHARACTERS); i= frequencies[0]-BB_THRESHOLD*pow(BB_SEMITONE, 0) && 51 | f <= frequencies[31]+BB_THRESHOLD*pow(BB_SEMITONE, 31)) { 52 | 53 | unsigned int i; 54 | 55 | for (i=0; i<32; i++) { 56 | 57 | unsigned int freq = (unsigned int)floor(BB_BASEFREQUENCY * pow(BB_SEMITONE, i)); 58 | frequencies[i] = freq; 59 | 60 | if (abs(frequencies[i] - f) <= BB_THRESHOLD*pow(BB_SEMITONE, i)) { 61 | //if (abs(frequencies[i] - f) <= BB_THRESHOLD) { 62 | *n = i; 63 | return 0; 64 | } 65 | } 66 | } 67 | */ 68 | 69 | freq_init(); 70 | 71 | 72 | if (n != NULL && 73 | f >= frequencies[0]-BB_THRESHOLD && 74 | f <= frequencies[31]+BB_THRESHOLD) { 75 | 76 | unsigned int i; 77 | 78 | for (i=0; i<32; i++) { 79 | 80 | if (abs(frequencies[i] - f) <= BB_THRESHOLD) { 81 | 82 | *n = i; 83 | return 0; 84 | } 85 | } 86 | } 87 | 88 | 89 | /* 90 | if (n!=NULL && f>freq_range[0].start && ffreq_range[i].start && f=0 && n<32) { 111 | 112 | *c = BB_CHARACTERS[n]; 113 | 114 | return 0; 115 | } 116 | 117 | return -1; 118 | } 119 | 120 | int char_to_num(char c, unsigned int *n) { 121 | 122 | if (n == NULL) return -1; 123 | 124 | *n = 0; 125 | 126 | if (c>=48 && c<=57) { 127 | 128 | *n = c - 48; 129 | 130 | return 0; 131 | 132 | } else if (c>=97 && c<=118) { 133 | 134 | *n = c - 87; 135 | 136 | return 0; 137 | } 138 | 139 | return -1; 140 | } 141 | 142 | int num_to_freq(int n, unsigned int *f) { 143 | 144 | freq_init(); 145 | 146 | if (f != NULL && n>=0 && n<32) { 147 | 148 | //*f = (unsigned int)floor(BB_BASEFREQUENCY * pow(BB_SEMITONE, n)); 149 | *f = (unsigned int)floor(frequencies[n]); 150 | 151 | 152 | return 0; 153 | } 154 | 155 | return -1; 156 | } 157 | 158 | int char_to_freq(char c, unsigned int *f) { 159 | 160 | unsigned int n; 161 | 162 | if (f != NULL && char_to_num(c, &n) == 0) { 163 | 164 | unsigned int ff; 165 | 166 | if (num_to_freq(n, &ff) == 0) { 167 | 168 | *f = ff; 169 | return 0; 170 | } 171 | } 172 | 173 | return -1; 174 | } 175 | 176 | 177 | 178 | // 一个频率对应的一组PCM的buffer 179 | int encode_sound(unsigned int freq, float buffer[], size_t buffer_length) { 180 | 181 | 182 | const double amplitude = 0.25; 183 | double theta_increment = 2.0 * PI * freq / SAMPLE_RATE; 184 | int frame; 185 | 186 | for (frame = 0; frame < buffer_length; frame++) { 187 | 188 | buffer[frame] = sin(theta) * amplitude; 189 | theta += theta_increment; 190 | 191 | if (theta > 2.0 * PI) { 192 | 193 | theta -= 2.0 * PI; 194 | } 195 | } 196 | 197 | return 1; 198 | } 199 | 200 | void _medianfilter(const element* signal, element* result, int N) 201 | { 202 | // Move window through all elements of the signal 203 | for (int i = 1; i < N - 1; ++i) 204 | { 205 | // Pick up window elements 206 | element window[3]; 207 | for (int j = 0; j < 3; ++j) 208 | window[j] = signal[i - 1 + j]; 209 | // Order elements (only half of them) 210 | for (int j = 0; j < 2; ++j) 211 | { 212 | // Find position of minimum element 213 | int min = j; 214 | for (int k = j + 1; k < 3; ++k) 215 | if (window[k] < window[min]) 216 | min = k; 217 | // Put found minimum element in its place 218 | const element temp = window[j]; 219 | window[j] = window[min]; 220 | window[min] = temp; 221 | } 222 | // Get result - the middle element 223 | result[i] = window[1]; 224 | } 225 | 226 | result[0] = signal[0]; 227 | } -------------------------------------------------------------------------------- /c/freq_util/freq_util.h: -------------------------------------------------------------------------------- 1 | // 2 | // bb_freq_util.h 3 | // BBSDK 4 | // 5 | // Created by Littlebox on 13-5-6. 6 | // Copyright (c) 2013年 Littlebox. All rights reserved. 7 | // 8 | 9 | #ifndef __freq_util__ 10 | #define __freq_util__ 11 | 12 | 13 | 14 | 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include 22 | #include 23 | 24 | 25 | 26 | #define PI 3.1415926535897932384626433832795028841971 //定义圆周率值 27 | #define SAMPLE_RATE 44100 //采样频率 28 | 29 | #define BB_SEMITONE 1.05946311 30 | #define BB_BASEFREQUENCY 1760 31 | #define BB_CHARACTERS "0123456789abcdefghijklmnopqrstuv" 32 | 33 | #define BB_FREQUENCIES {1765,1856,1986,2130,2211,2363,2492,2643,2799,2964,3243,3316,3482,3751,3987,4192,4430,4794,5000,5449,5598,5900,6262,6627,7004,7450,7881,8174,8906,9423,9948,10536} 34 | 35 | #define BB_THRESHOLD 16 36 | 37 | #define BB_HEADER_0 17 38 | #define BB_HEADER_1 19 39 | 40 | 41 | typedef float element; 42 | 43 | //void freq_init(); 44 | 45 | int freq_to_num(unsigned int f, int *n); 46 | 47 | int num_to_char(int n, char *c); 48 | 49 | int char_to_num(char c, unsigned int *n); 50 | 51 | int num_to_freq(int n, unsigned int *f); 52 | 53 | int char_to_freq(char c, unsigned int *f); 54 | 55 | void _medianfilter(const element* signal, element* result, int N); 56 | 57 | int encode_sound(unsigned int freq, float buffer[], size_t buffer_length); 58 | 59 | #endif /* __freq_util__ */ 60 | 61 | 62 | 63 | 64 | -------------------------------------------------------------------------------- /c/kiss_fft/_kiss_fft_guts.h: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2003-2010, Mark Borgerding 3 | 4 | All rights reserved. 5 | 6 | Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 7 | 8 | * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 9 | * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 10 | * Neither the author nor the names of any contributors may be used to endorse or promote products derived from this software without specific prior written permission. 11 | 12 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 13 | */ 14 | 15 | /* kiss_fft.h 16 | defines kiss_fft_scalar as either short or a float type 17 | and defines 18 | typedef struct { kiss_fft_scalar r; kiss_fft_scalar i; }kiss_fft_cpx; */ 19 | #include "kiss_fft.h" 20 | #include 21 | 22 | #define MAXFACTORS 32 23 | /* e.g. an fft of length 128 has 4 factors 24 | as far as kissfft is concerned 25 | 4*4*4*2 26 | */ 27 | 28 | #define BB_MAX_FFT_SIZE 4096 29 | 30 | struct kiss_fft_state{ 31 | int nfft; 32 | int inverse; 33 | int factors[2*MAXFACTORS]; 34 | kiss_fft_cpx twiddles[1]; 35 | }; 36 | 37 | /* 38 | Explanation of macros dealing with complex math: 39 | 40 | C_MUL(m,a,b) : m = a*b 41 | C_FIXDIV( c , div ) : if a fixed point impl., c /= div. noop otherwise 42 | C_SUB( res, a,b) : res = a - b 43 | C_SUBFROM( res , a) : res -= a 44 | C_ADDTO( res , a) : res += a 45 | * */ 46 | #ifdef FIXED_POINT 47 | #if (FIXED_POINT==32) 48 | # define FRACBITS 31 49 | # define SAMPPROD int64_t 50 | #define SAMP_MAX 2147483647 51 | #else 52 | # define FRACBITS 15 53 | # define SAMPPROD int32_t 54 | #define SAMP_MAX 32767 55 | #endif 56 | 57 | #define SAMP_MIN -SAMP_MAX 58 | 59 | #if defined(CHECK_OVERFLOW) 60 | # define CHECK_OVERFLOW_OP(a,op,b) \ 61 | if ( (SAMPPROD)(a) op (SAMPPROD)(b) > SAMP_MAX || (SAMPPROD)(a) op (SAMPPROD)(b) < SAMP_MIN ) { \ 62 | fprintf(stderr,"WARNING:overflow @ " __FILE__ "(%d): (%d " #op" %d) = %ld\n",__LINE__,(a),(b),(SAMPPROD)(a) op (SAMPPROD)(b) ); } 63 | #endif 64 | 65 | 66 | # define smul(a,b) ( (SAMPPROD)(a)*(b) ) 67 | # define sround( x ) (kiss_fft_scalar)( ( (x) + (1<<(FRACBITS-1)) ) >> FRACBITS ) 68 | 69 | # define S_MUL(a,b) sround( smul(a,b) ) 70 | 71 | # define C_MUL(m,a,b) \ 72 | do{ (m).r = sround( smul((a).r,(b).r) - smul((a).i,(b).i) ); \ 73 | (m).i = sround( smul((a).r,(b).i) + smul((a).i,(b).r) ); }while(0) 74 | 75 | # define DIVSCALAR(x,k) \ 76 | (x) = sround( smul( x, SAMP_MAX/k ) ) 77 | 78 | # define C_FIXDIV(c,div) \ 79 | do { DIVSCALAR( (c).r , div); \ 80 | DIVSCALAR( (c).i , div); }while (0) 81 | 82 | # define C_MULBYSCALAR( c, s ) \ 83 | do{ (c).r = sround( smul( (c).r , s ) ) ;\ 84 | (c).i = sround( smul( (c).i , s ) ) ; }while(0) 85 | 86 | #else /* not FIXED_POINT*/ 87 | 88 | # define S_MUL(a,b) ( (a)*(b) ) 89 | #define C_MUL(m,a,b) \ 90 | do{ (m).r = (a).r*(b).r - (a).i*(b).i;\ 91 | (m).i = (a).r*(b).i + (a).i*(b).r; }while(0) 92 | # define C_FIXDIV(c,div) /* NOOP */ 93 | # define C_MULBYSCALAR( c, s ) \ 94 | do{ (c).r *= (s);\ 95 | (c).i *= (s); }while(0) 96 | #endif 97 | 98 | #ifndef CHECK_OVERFLOW_OP 99 | # define CHECK_OVERFLOW_OP(a,op,b) /* noop */ 100 | #endif 101 | 102 | #define C_ADD( res, a,b)\ 103 | do { \ 104 | CHECK_OVERFLOW_OP((a).r,+,(b).r)\ 105 | CHECK_OVERFLOW_OP((a).i,+,(b).i)\ 106 | (res).r=(a).r+(b).r; (res).i=(a).i+(b).i; \ 107 | }while(0) 108 | #define C_SUB( res, a,b)\ 109 | do { \ 110 | CHECK_OVERFLOW_OP((a).r,-,(b).r)\ 111 | CHECK_OVERFLOW_OP((a).i,-,(b).i)\ 112 | (res).r=(a).r-(b).r; (res).i=(a).i-(b).i; \ 113 | }while(0) 114 | #define C_ADDTO( res , a)\ 115 | do { \ 116 | CHECK_OVERFLOW_OP((res).r,+,(a).r)\ 117 | CHECK_OVERFLOW_OP((res).i,+,(a).i)\ 118 | (res).r += (a).r; (res).i += (a).i;\ 119 | }while(0) 120 | 121 | #define C_SUBFROM( res , a)\ 122 | do {\ 123 | CHECK_OVERFLOW_OP((res).r,-,(a).r)\ 124 | CHECK_OVERFLOW_OP((res).i,-,(a).i)\ 125 | (res).r -= (a).r; (res).i -= (a).i; \ 126 | }while(0) 127 | 128 | 129 | #ifdef FIXED_POINT 130 | # define KISS_FFT_COS(phase) floor(.5+SAMP_MAX * cos (phase)) 131 | # define KISS_FFT_SIN(phase) floor(.5+SAMP_MAX * sin (phase)) 132 | # define HALF_OF(x) ((x)>>1) 133 | #elif defined(USE_SIMD) 134 | # define KISS_FFT_COS(phase) _mm_set1_ps( cos(phase) ) 135 | # define KISS_FFT_SIN(phase) _mm_set1_ps( sin(phase) ) 136 | # define HALF_OF(x) ((x)*_mm_set1_ps(.5)) 137 | #else 138 | # define KISS_FFT_COS(phase) (kiss_fft_scalar) cos(phase) 139 | # define KISS_FFT_SIN(phase) (kiss_fft_scalar) sin(phase) 140 | # define HALF_OF(x) ((x)*.5) 141 | #endif 142 | 143 | #define kf_cexp(x,phase) \ 144 | do{ \ 145 | (x)->r = KISS_FFT_COS(phase);\ 146 | (x)->i = KISS_FFT_SIN(phase);\ 147 | }while(0) 148 | 149 | 150 | /* a debugging function */ 151 | #define pcpx(c)\ 152 | fprintf(stderr,"%g + %gi\n",(double)((c)->r),(double)((c)->i) ) 153 | 154 | 155 | #ifdef KISS_FFT_USE_ALLOCA 156 | // define this to allow use of alloca instead of malloc for temporary buffers 157 | // Temporary buffers are used in two case: 158 | // 1. FFT sizes that have "bad" factors. i.e. not 2,3 and 5 159 | // 2. "in-place" FFTs. Notice the quotes, since kissfft does not really do an in-place transform. 160 | #include 161 | #define KISS_FFT_TMP_ALLOC(nbytes) alloca(nbytes) 162 | #define KISS_FFT_TMP_FREE(ptr) 163 | #else 164 | #define KISS_FFT_TMP_ALLOC(nbytes) KISS_FFT_MALLOC(nbytes) 165 | #define KISS_FFT_TMP_FREE(ptr) KISS_FFT_FREE(ptr) 166 | #endif 167 | -------------------------------------------------------------------------------- /c/kiss_fft/kiss_fastfir.c: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2003-2004, Mark Borgerding 3 | 4 | All rights reserved. 5 | 6 | Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 7 | 8 | * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 9 | * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 10 | * Neither the author nor the names of any contributors may be used to endorse or promote products derived from this software without specific prior written permission. 11 | 12 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 13 | */ 14 | 15 | #include "_kiss_fft_guts.h" 16 | #include "kiss_fastfir.h" 17 | 18 | 19 | 20 | //static int verbose=0; 21 | 22 | 23 | struct kiss_fastfir_state{ 24 | size_t nfft; 25 | size_t ngood; 26 | kfcfg_t fftcfg; 27 | kfcfg_t ifftcfg; 28 | kiss_fft_cpx * fir_freq_resp; 29 | kiss_fft_cpx * freqbuf; 30 | size_t n_freq_bins; 31 | kffsamp_t * tmpbuf; 32 | }; 33 | 34 | 35 | kiss_fastfir_cfg kiss_fastfir_alloc( 36 | const kffsamp_t * imp_resp,size_t n_imp_resp, 37 | size_t *pnfft, /* if <= 0, an appropriate size will be chosen */ 38 | void * mem,size_t*lenmem) 39 | { 40 | kiss_fastfir_cfg st = NULL; 41 | size_t len_fftcfg,len_ifftcfg; 42 | size_t memneeded = sizeof(struct kiss_fastfir_state); 43 | char * ptr; 44 | size_t i; 45 | size_t nfft=0; 46 | float scale; 47 | int n_freq_bins; 48 | if (pnfft) 49 | nfft=*pnfft; 50 | 51 | if (nfft<=0) { 52 | /* determine fft size as next power of two at least 2x 53 | the impulse response length*/ 54 | i=n_imp_resp-1; 55 | nfft=2; 56 | do{ 57 | nfft<<=1; 58 | }while (i>>=1); 59 | #ifdef MIN_FFT_LEN 60 | if ( nfft < MIN_FFT_LEN ) 61 | nfft=MIN_FFT_LEN; 62 | #endif 63 | } 64 | if (pnfft) 65 | *pnfft = nfft; 66 | 67 | #ifdef REAL_FASTFIR 68 | n_freq_bins = nfft/2 + 1; 69 | #else 70 | n_freq_bins = nfft; 71 | #endif 72 | /*fftcfg*/ 73 | FFT_ALLOC (nfft, 0, NULL, &len_fftcfg); 74 | memneeded += len_fftcfg; 75 | /*ifftcfg*/ 76 | FFT_ALLOC (nfft, 1, NULL, &len_ifftcfg); 77 | memneeded += len_ifftcfg; 78 | /* tmpbuf */ 79 | memneeded += sizeof(kffsamp_t) * nfft; 80 | /* fir_freq_resp */ 81 | memneeded += sizeof(kiss_fft_cpx) * n_freq_bins; 82 | /* freqbuf */ 83 | memneeded += sizeof(kiss_fft_cpx) * n_freq_bins; 84 | 85 | if (lenmem == NULL) { 86 | st = (kiss_fastfir_cfg) malloc (memneeded); 87 | } else { 88 | if (*lenmem >= memneeded) 89 | st = (kiss_fastfir_cfg) mem; 90 | *lenmem = memneeded; 91 | } 92 | if (!st) 93 | return NULL; 94 | 95 | st->nfft = nfft; 96 | st->ngood = nfft - n_imp_resp + 1; 97 | st->n_freq_bins = n_freq_bins; 98 | ptr=(char*)(st+1); 99 | 100 | st->fftcfg = (kfcfg_t)ptr; 101 | ptr += len_fftcfg; 102 | 103 | st->ifftcfg = (kfcfg_t)ptr; 104 | ptr += len_ifftcfg; 105 | 106 | st->tmpbuf = (kffsamp_t*)ptr; 107 | ptr += sizeof(kffsamp_t) * nfft; 108 | 109 | st->freqbuf = (kiss_fft_cpx*)ptr; 110 | ptr += sizeof(kiss_fft_cpx) * n_freq_bins; 111 | 112 | st->fir_freq_resp = (kiss_fft_cpx*)ptr; 113 | ptr += sizeof(kiss_fft_cpx) * n_freq_bins; 114 | 115 | FFT_ALLOC (nfft,0,st->fftcfg , &len_fftcfg); 116 | FFT_ALLOC (nfft,1,st->ifftcfg , &len_ifftcfg); 117 | 118 | memset(st->tmpbuf,0,sizeof(kffsamp_t)*nfft); 119 | /*zero pad in the middle to left-rotate the impulse response 120 | This puts the scrap samples at the end of the inverse fft'd buffer */ 121 | st->tmpbuf[0] = imp_resp[ n_imp_resp - 1 ]; 122 | for (i=0;itmpbuf[ nfft - n_imp_resp + 1 + i ] = imp_resp[ i ]; 124 | } 125 | 126 | FFTFWD(st->fftcfg,st->tmpbuf,st->fir_freq_resp); 127 | 128 | /* TODO: this won't work for fixed point */ 129 | scale = 1.0 / st->nfft; 130 | 131 | for ( i=0; i < st->n_freq_bins; ++i ) { 132 | #ifdef USE_SIMD 133 | st->fir_freq_resp[i].r *= _mm_set1_ps(scale); 134 | st->fir_freq_resp[i].i *= _mm_set1_ps(scale); 135 | #else 136 | st->fir_freq_resp[i].r *= scale; 137 | st->fir_freq_resp[i].i *= scale; 138 | #endif 139 | } 140 | return st; 141 | } 142 | 143 | static void fastconv1buf(const kiss_fastfir_cfg st,const kffsamp_t * in,kffsamp_t * out) 144 | { 145 | size_t i; 146 | /* multiply the frequency response of the input signal by 147 | that of the fir filter*/ 148 | FFTFWD( st->fftcfg, in , st->freqbuf ); 149 | for ( i=0; in_freq_bins; ++i ) { 150 | kiss_fft_cpx tmpsamp; 151 | C_MUL(tmpsamp,st->freqbuf[i],st->fir_freq_resp[i]); 152 | st->freqbuf[i] = tmpsamp; 153 | } 154 | 155 | /* perform the inverse fft*/ 156 | FFTINV(st->ifftcfg,st->freqbuf,out); 157 | } 158 | 159 | /* n : the size of inbuf and outbuf in samples 160 | return value: the number of samples completely processed 161 | n-retval samples should be copied to the front of the next input buffer */ 162 | static size_t kff_nocopy( 163 | kiss_fastfir_cfg st, 164 | const kffsamp_t * inbuf, 165 | kffsamp_t * outbuf, 166 | size_t n) 167 | { 168 | size_t norig=n; 169 | while (n >= st->nfft ) { 170 | fastconv1buf(st,inbuf,outbuf); 171 | inbuf += st->ngood; 172 | outbuf += st->ngood; 173 | n -= st->ngood; 174 | } 175 | return norig - n; 176 | } 177 | 178 | static 179 | size_t kff_flush(kiss_fastfir_cfg st,const kffsamp_t * inbuf,kffsamp_t * outbuf,size_t n) 180 | { 181 | size_t zpad=0,ntmp; 182 | 183 | ntmp = kff_nocopy(st,inbuf,outbuf,n); 184 | n -= ntmp; 185 | inbuf += ntmp; 186 | outbuf += ntmp; 187 | 188 | zpad = st->nfft - n; 189 | memset(st->tmpbuf,0,sizeof(kffsamp_t)*st->nfft ); 190 | memcpy(st->tmpbuf,inbuf,sizeof(kffsamp_t)*n ); 191 | 192 | fastconv1buf(st,st->tmpbuf,st->tmpbuf); 193 | 194 | memcpy(outbuf,st->tmpbuf,sizeof(kffsamp_t)*( st->ngood - zpad )); 195 | return ntmp + st->ngood - zpad; 196 | } 197 | 198 | size_t kiss_fastfir( 199 | kiss_fastfir_cfg vst, 200 | kffsamp_t * inbuf, 201 | kffsamp_t * outbuf, 202 | size_t n_new, 203 | size_t *offset) 204 | { 205 | size_t ntot = n_new + *offset; 206 | if (n_new==0) { 207 | return kff_flush(vst,inbuf,outbuf,ntot); 208 | }else{ 209 | size_t nwritten = kff_nocopy(vst,inbuf,outbuf,ntot); 210 | *offset = ntot - nwritten; 211 | /*save the unused or underused samples at the front of the input buffer */ 212 | memcpy( inbuf , inbuf+nwritten , *offset * sizeof(kffsamp_t) ); 213 | return nwritten; 214 | } 215 | } 216 | 217 | #ifdef FAST_FILT_UTIL 218 | #include 219 | #include 220 | #include 221 | #include 222 | 223 | static 224 | void direct_file_filter( 225 | FILE * fin, 226 | FILE * fout, 227 | const kffsamp_t * imp_resp, 228 | size_t n_imp_resp) 229 | { 230 | size_t nlag = n_imp_resp - 1; 231 | 232 | const kffsamp_t *tmph; 233 | kffsamp_t *buf, *circbuf; 234 | kffsamp_t outval; 235 | size_t nread; 236 | size_t nbuf; 237 | size_t oldestlag = 0; 238 | size_t k, tap; 239 | #ifndef REAL_FASTFIR 240 | kffsamp_t tmp; 241 | #endif 242 | 243 | nbuf = 4096; 244 | buf = (kffsamp_t *) malloc ( sizeof (kffsamp_t) * nbuf); 245 | circbuf = (kffsamp_t *) malloc (sizeof (kffsamp_t) * nlag); 246 | if (!circbuf || !buf) { 247 | perror("circbuf allocation"); 248 | exit(1); 249 | } 250 | 251 | if ( fread (circbuf, sizeof (kffsamp_t), nlag, fin) != nlag ) { 252 | perror ("insufficient data to overcome transient"); 253 | exit (1); 254 | } 255 | 256 | do { 257 | nread = fread (buf, sizeof (kffsamp_t), nbuf, fin); 258 | if (nread <= 0) 259 | break; 260 | 261 | for (k = 0; k < nread; ++k) { 262 | tmph = imp_resp+nlag; 263 | #ifdef REAL_FASTFIR 264 | # ifdef USE_SIMD 265 | outval = _mm_set1_ps(0); 266 | #else 267 | outval = 0; 268 | #endif 269 | for (tap = oldestlag; tap < nlag; ++tap) 270 | outval += circbuf[tap] * *tmph--; 271 | for (tap = 0; tap < oldestlag; ++tap) 272 | outval += circbuf[tap] * *tmph--; 273 | outval += buf[k] * *tmph; 274 | #else 275 | # ifdef USE_SIMD 276 | outval.r = outval.i = _mm_set1_ps(0); 277 | #else 278 | outval.r = outval.i = 0; 279 | #endif 280 | for (tap = oldestlag; tap < nlag; ++tap){ 281 | C_MUL(tmp,circbuf[tap],*tmph); 282 | --tmph; 283 | C_ADDTO(outval,tmp); 284 | } 285 | 286 | for (tap = 0; tap < oldestlag; ++tap) { 287 | C_MUL(tmp,circbuf[tap],*tmph); 288 | --tmph; 289 | C_ADDTO(outval,tmp); 290 | } 291 | C_MUL(tmp,buf[k],*tmph); 292 | C_ADDTO(outval,tmp); 293 | #endif 294 | 295 | circbuf[oldestlag++] = buf[k]; 296 | buf[k] = outval; 297 | 298 | if (oldestlag == nlag) 299 | oldestlag = 0; 300 | } 301 | 302 | if (fwrite (buf, sizeof (buf[0]), nread, fout) != nread) { 303 | perror ("short write"); 304 | exit (1); 305 | } 306 | } while (nread); 307 | free (buf); 308 | free (circbuf); 309 | } 310 | 311 | static 312 | void do_file_filter( 313 | FILE * fin, 314 | FILE * fout, 315 | const kffsamp_t * imp_resp, 316 | size_t n_imp_resp, 317 | size_t nfft ) 318 | { 319 | int fdout; 320 | size_t n_samps_buf; 321 | 322 | kiss_fastfir_cfg cfg; 323 | kffsamp_t *inbuf,*outbuf; 324 | int nread,nwrite; 325 | size_t idx_inbuf; 326 | 327 | fdout = fileno(fout); 328 | 329 | cfg=kiss_fastfir_alloc(imp_resp,n_imp_resp,&nfft,0,0); 330 | 331 | /* use length to minimize buffer shift*/ 332 | n_samps_buf = 8*4096/sizeof(kffsamp_t); 333 | n_samps_buf = nfft + 4*(nfft-n_imp_resp+1); 334 | 335 | if (verbose) fprintf(stderr,"bufsize=%d\n",(int)(sizeof(kffsamp_t)*n_samps_buf) ); 336 | 337 | 338 | /*allocate space and initialize pointers */ 339 | inbuf = (kffsamp_t*)malloc(sizeof(kffsamp_t)*n_samps_buf); 340 | outbuf = (kffsamp_t*)malloc(sizeof(kffsamp_t)*n_samps_buf); 341 | 342 | idx_inbuf=0; 343 | do{ 344 | /* start reading at inbuf[idx_inbuf] */ 345 | nread = fread( inbuf + idx_inbuf, sizeof(kffsamp_t), n_samps_buf - idx_inbuf,fin ); 346 | 347 | /* If nread==0, then this is a flush. 348 | The total number of samples in input is idx_inbuf + nread . */ 349 | nwrite = kiss_fastfir(cfg, inbuf, outbuf,nread,&idx_inbuf) * sizeof(kffsamp_t); 350 | /* kiss_fastfir moved any unused samples to the front of inbuf and updated idx_inbuf */ 351 | 352 | if ( write(fdout, outbuf, nwrite) != nwrite ) { 353 | perror("short write"); 354 | exit(1); 355 | } 356 | }while ( nread ); 357 | free(cfg); 358 | free(inbuf); 359 | free(outbuf); 360 | } 361 | 362 | int main(int argc,char**argv) 363 | { 364 | kffsamp_t * h; 365 | int use_direct=0; 366 | size_t nh,nfft=0; 367 | FILE *fin=stdin; 368 | FILE *fout=stdout; 369 | FILE *filtfile=NULL; 370 | while (1) { 371 | int c=getopt(argc,argv,"n:h:i:o:vd"); 372 | if (c==-1) break; 373 | switch (c) { 374 | case 'v': 375 | verbose=1; 376 | break; 377 | case 'n': 378 | nfft=atoi(optarg); 379 | break; 380 | case 'i': 381 | fin = fopen(optarg,"rb"); 382 | if (fin==NULL) { 383 | perror(optarg); 384 | exit(1); 385 | } 386 | break; 387 | case 'o': 388 | fout = fopen(optarg,"w+b"); 389 | if (fout==NULL) { 390 | perror(optarg); 391 | exit(1); 392 | } 393 | break; 394 | case 'h': 395 | filtfile = fopen(optarg,"rb"); 396 | if (filtfile==NULL) { 397 | perror(optarg); 398 | exit(1); 399 | } 400 | break; 401 | case 'd': 402 | use_direct=1; 403 | break; 404 | case '?': 405 | fprintf(stderr,"usage options:\n" 406 | "\t-n nfft: fft size to use\n" 407 | "\t-d : use direct FIR filtering, not fast convolution\n" 408 | "\t-i filename: input file\n" 409 | "\t-o filename: output(filtered) file\n" 410 | "\t-n nfft: fft size to use\n" 411 | "\t-h filename: impulse response\n"); 412 | exit (1); 413 | default:fprintf(stderr,"bad %c\n",c);break; 414 | } 415 | } 416 | if (filtfile==NULL) { 417 | fprintf(stderr,"You must supply the FIR coeffs via -h\n"); 418 | exit(1); 419 | } 420 | fseek(filtfile,0,SEEK_END); 421 | nh = ftell(filtfile) / sizeof(kffsamp_t); 422 | if (verbose) fprintf(stderr,"%d samples in FIR filter\n",(int)nh); 423 | h = (kffsamp_t*)malloc(sizeof(kffsamp_t)*nh); 424 | fseek(filtfile,0,SEEK_SET); 425 | if (fread(h,sizeof(kffsamp_t),nh,filtfile) != nh) 426 | fprintf(stderr,"short read on filter file\n"); 427 | 428 | fclose(filtfile); 429 | 430 | if (use_direct) 431 | direct_file_filter( fin, fout, h,nh); 432 | else 433 | do_file_filter( fin, fout, h,nh,nfft); 434 | 435 | if (fout!=stdout) fclose(fout); 436 | if (fin!=stdin) fclose(fin); 437 | 438 | return 0; 439 | } 440 | #endif 441 | -------------------------------------------------------------------------------- /c/kiss_fft/kiss_fastfir.h: -------------------------------------------------------------------------------- 1 | // 2 | // kiss_fastfir.h 3 | // BBSDK 4 | // 5 | // Created by Bruce on 13-5-22. 6 | // Copyright (c) 2013年 Littlebox. All rights reserved. 7 | // 8 | 9 | #ifndef BBSDK_kiss_fastfir_h 10 | #define BBSDK_kiss_fastfir_h 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | /* 25 | Some definitions that allow real or complex filtering 26 | */ 27 | #ifdef REAL_FASTFIR 28 | #define MIN_FFT_LEN 2048 29 | #include "kiss_fftr.h" 30 | 31 | typedef kiss_fft_scalar kffsamp_t; 32 | typedef kiss_fftr_cfg kfcfg_t; 33 | #define FFT_ALLOC kiss_fftr_alloc 34 | #define FFTFWD kiss_fftr 35 | #define FFTINV kiss_fftri 36 | #else 37 | #define MIN_FFT_LEN 1024 38 | typedef kiss_fft_cpx kffsamp_t; 39 | typedef kiss_fft_cfg kfcfg_t; 40 | #define FFT_ALLOC kiss_fft_alloc 41 | #define FFTFWD kiss_fft 42 | #define FFTINV kiss_fft 43 | #endif 44 | 45 | typedef struct kiss_fastfir_state *kiss_fastfir_cfg; 46 | 47 | 48 | 49 | kiss_fastfir_cfg kiss_fastfir_alloc(const kffsamp_t * imp_resp,size_t n_imp_resp, 50 | size_t * nfft,void * mem,size_t*lenmem); 51 | 52 | /* see do_file_filter for usage */ 53 | size_t kiss_fastfir( kiss_fastfir_cfg cfg, kffsamp_t * inbuf, kffsamp_t * outbuf, size_t n, size_t *offset); 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | #endif 74 | -------------------------------------------------------------------------------- /c/kiss_fft/kiss_fft.c: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2003-2010, Mark Borgerding 3 | 4 | All rights reserved. 5 | 6 | Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 7 | 8 | * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 9 | * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 10 | * Neither the author nor the names of any contributors may be used to endorse or promote products derived from this software without specific prior written permission. 11 | 12 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 13 | */ 14 | 15 | 16 | #include "_kiss_fft_guts.h" 17 | /* The guts header contains all the multiplication and addition macros that are defined for 18 | fixed or floating point complex numbers. It also delares the kf_ internal functions. 19 | */ 20 | 21 | static void kf_bfly2( 22 | kiss_fft_cpx * Fout, 23 | const size_t fstride, 24 | const kiss_fft_cfg st, 25 | int m 26 | ) 27 | { 28 | kiss_fft_cpx * Fout2; 29 | kiss_fft_cpx * tw1 = st->twiddles; 30 | kiss_fft_cpx t; 31 | Fout2 = Fout + m; 32 | do{ 33 | C_FIXDIV(*Fout,2); C_FIXDIV(*Fout2,2); 34 | 35 | C_MUL (t, *Fout2 , *tw1); 36 | tw1 += fstride; 37 | C_SUB( *Fout2 , *Fout , t ); 38 | C_ADDTO( *Fout , t ); 39 | ++Fout2; 40 | ++Fout; 41 | }while (--m); 42 | } 43 | 44 | static void kf_bfly4( 45 | kiss_fft_cpx * Fout, 46 | const size_t fstride, 47 | const kiss_fft_cfg st, 48 | const size_t m 49 | ) 50 | { 51 | kiss_fft_cpx *tw1,*tw2,*tw3; 52 | kiss_fft_cpx scratch[6]; 53 | size_t k=m; 54 | const size_t m2=2*m; 55 | const size_t m3=3*m; 56 | 57 | 58 | tw3 = tw2 = tw1 = st->twiddles; 59 | 60 | do { 61 | C_FIXDIV(*Fout,4); C_FIXDIV(Fout[m],4); C_FIXDIV(Fout[m2],4); C_FIXDIV(Fout[m3],4); 62 | 63 | C_MUL(scratch[0],Fout[m] , *tw1 ); 64 | C_MUL(scratch[1],Fout[m2] , *tw2 ); 65 | C_MUL(scratch[2],Fout[m3] , *tw3 ); 66 | 67 | C_SUB( scratch[5] , *Fout, scratch[1] ); 68 | C_ADDTO(*Fout, scratch[1]); 69 | C_ADD( scratch[3] , scratch[0] , scratch[2] ); 70 | C_SUB( scratch[4] , scratch[0] , scratch[2] ); 71 | C_SUB( Fout[m2], *Fout, scratch[3] ); 72 | tw1 += fstride; 73 | tw2 += fstride*2; 74 | tw3 += fstride*3; 75 | C_ADDTO( *Fout , scratch[3] ); 76 | 77 | if(st->inverse) { 78 | Fout[m].r = scratch[5].r - scratch[4].i; 79 | Fout[m].i = scratch[5].i + scratch[4].r; 80 | Fout[m3].r = scratch[5].r + scratch[4].i; 81 | Fout[m3].i = scratch[5].i - scratch[4].r; 82 | }else{ 83 | Fout[m].r = scratch[5].r + scratch[4].i; 84 | Fout[m].i = scratch[5].i - scratch[4].r; 85 | Fout[m3].r = scratch[5].r - scratch[4].i; 86 | Fout[m3].i = scratch[5].i + scratch[4].r; 87 | } 88 | ++Fout; 89 | }while(--k); 90 | } 91 | 92 | static void kf_bfly3( 93 | kiss_fft_cpx * Fout, 94 | const size_t fstride, 95 | const kiss_fft_cfg st, 96 | size_t m 97 | ) 98 | { 99 | size_t k=m; 100 | const size_t m2 = 2*m; 101 | kiss_fft_cpx *tw1,*tw2; 102 | kiss_fft_cpx scratch[5]; 103 | kiss_fft_cpx epi3; 104 | epi3 = st->twiddles[fstride*m]; 105 | 106 | tw1=tw2=st->twiddles; 107 | 108 | do{ 109 | C_FIXDIV(*Fout,3); C_FIXDIV(Fout[m],3); C_FIXDIV(Fout[m2],3); 110 | 111 | C_MUL(scratch[1],Fout[m] , *tw1); 112 | C_MUL(scratch[2],Fout[m2] , *tw2); 113 | 114 | C_ADD(scratch[3],scratch[1],scratch[2]); 115 | C_SUB(scratch[0],scratch[1],scratch[2]); 116 | tw1 += fstride; 117 | tw2 += fstride*2; 118 | 119 | Fout[m].r = Fout->r - HALF_OF(scratch[3].r); 120 | Fout[m].i = Fout->i - HALF_OF(scratch[3].i); 121 | 122 | C_MULBYSCALAR( scratch[0] , epi3.i ); 123 | 124 | C_ADDTO(*Fout,scratch[3]); 125 | 126 | Fout[m2].r = Fout[m].r + scratch[0].i; 127 | Fout[m2].i = Fout[m].i - scratch[0].r; 128 | 129 | Fout[m].r -= scratch[0].i; 130 | Fout[m].i += scratch[0].r; 131 | 132 | ++Fout; 133 | }while(--k); 134 | } 135 | 136 | static void kf_bfly5( 137 | kiss_fft_cpx * Fout, 138 | const size_t fstride, 139 | const kiss_fft_cfg st, 140 | int m 141 | ) 142 | { 143 | kiss_fft_cpx *Fout0,*Fout1,*Fout2,*Fout3,*Fout4; 144 | int u; 145 | kiss_fft_cpx scratch[13]; 146 | kiss_fft_cpx * twiddles = st->twiddles; 147 | kiss_fft_cpx *tw; 148 | kiss_fft_cpx ya,yb; 149 | ya = twiddles[fstride*m]; 150 | yb = twiddles[fstride*2*m]; 151 | 152 | Fout0=Fout; 153 | Fout1=Fout0+m; 154 | Fout2=Fout0+2*m; 155 | Fout3=Fout0+3*m; 156 | Fout4=Fout0+4*m; 157 | 158 | tw=st->twiddles; 159 | for ( u=0; ur += scratch[7].r + scratch[8].r; 174 | Fout0->i += scratch[7].i + scratch[8].i; 175 | 176 | scratch[5].r = scratch[0].r + S_MUL(scratch[7].r,ya.r) + S_MUL(scratch[8].r,yb.r); 177 | scratch[5].i = scratch[0].i + S_MUL(scratch[7].i,ya.r) + S_MUL(scratch[8].i,yb.r); 178 | 179 | scratch[6].r = S_MUL(scratch[10].i,ya.i) + S_MUL(scratch[9].i,yb.i); 180 | scratch[6].i = -S_MUL(scratch[10].r,ya.i) - S_MUL(scratch[9].r,yb.i); 181 | 182 | C_SUB(*Fout1,scratch[5],scratch[6]); 183 | C_ADD(*Fout4,scratch[5],scratch[6]); 184 | 185 | scratch[11].r = scratch[0].r + S_MUL(scratch[7].r,yb.r) + S_MUL(scratch[8].r,ya.r); 186 | scratch[11].i = scratch[0].i + S_MUL(scratch[7].i,yb.r) + S_MUL(scratch[8].i,ya.r); 187 | scratch[12].r = - S_MUL(scratch[10].i,yb.i) + S_MUL(scratch[9].i,ya.i); 188 | scratch[12].i = S_MUL(scratch[10].r,yb.i) - S_MUL(scratch[9].r,ya.i); 189 | 190 | C_ADD(*Fout2,scratch[11],scratch[12]); 191 | C_SUB(*Fout3,scratch[11],scratch[12]); 192 | 193 | ++Fout0;++Fout1;++Fout2;++Fout3;++Fout4; 194 | } 195 | } 196 | 197 | /* perform the butterfly for one stage of a mixed radix FFT */ 198 | static void kf_bfly_generic( 199 | kiss_fft_cpx * Fout, 200 | const size_t fstride, 201 | const kiss_fft_cfg st, 202 | int m, 203 | int p 204 | ) 205 | { 206 | int u,k,q1,q; 207 | kiss_fft_cpx * twiddles = st->twiddles; 208 | kiss_fft_cpx t; 209 | int Norig = st->nfft; 210 | 211 | kiss_fft_cpx * scratch = (kiss_fft_cpx*)KISS_FFT_TMP_ALLOC(sizeof(kiss_fft_cpx)*p); 212 | 213 | for ( u=0; u=Norig) twidx-=Norig; 228 | C_MUL(t,scratch[q] , twiddles[twidx] ); 229 | C_ADDTO( Fout[ k ] ,t); 230 | } 231 | k += m; 232 | } 233 | } 234 | KISS_FFT_TMP_FREE(scratch); 235 | } 236 | 237 | static 238 | void kf_work( 239 | kiss_fft_cpx * Fout, 240 | const kiss_fft_cpx * f, 241 | const size_t fstride, 242 | int in_stride, 243 | int * factors, 244 | const kiss_fft_cfg st 245 | ) 246 | { 247 | kiss_fft_cpx * Fout_beg=Fout; 248 | const int p=*factors++; /* the radix */ 249 | const int m=*factors++; /* stage's fft length/p */ 250 | const kiss_fft_cpx * Fout_end = Fout + p*m; 251 | 252 | #ifdef _OPENMP 253 | // use openmp extensions at the 254 | // top-level (not recursive) 255 | if (fstride==1 && p<=5) 256 | { 257 | int k; 258 | 259 | // execute the p different work units in different threads 260 | # pragma omp parallel for 261 | for (k=0;k floor_sqrt) 324 | p = n; /* no more factors, skip to end */ 325 | } 326 | n /= p; 327 | *facbuf++ = p; 328 | *facbuf++ = n; 329 | } while (n > 1); 330 | } 331 | 332 | /* 333 | * 334 | * User-callable function to allocate all necessary storage space for the fft. 335 | * 336 | * The return value is a contiguous block of memory, allocated with malloc. As such, 337 | * It can be freed with free(), rather than a kiss_fft-specific function. 338 | * */ 339 | kiss_fft_cfg kiss_fft_alloc(int nfft,int inverse_fft,void * mem,size_t * lenmem ) 340 | { 341 | kiss_fft_cfg st=NULL; 342 | size_t memneeded = sizeof(struct kiss_fft_state) 343 | + sizeof(kiss_fft_cpx)*(nfft-1); /* twiddle factors*/ 344 | 345 | if ( lenmem==NULL ) { 346 | st = ( kiss_fft_cfg)KISS_FFT_MALLOC( memneeded ); 347 | }else{ 348 | if (mem != NULL && *lenmem >= memneeded) 349 | st = (kiss_fft_cfg)mem; 350 | *lenmem = memneeded; 351 | } 352 | if (st) { 353 | int i; 354 | st->nfft=nfft; 355 | st->inverse = inverse_fft; 356 | 357 | for (i=0;iinverse) 361 | phase *= -1; 362 | kf_cexp(st->twiddles+i, phase ); 363 | } 364 | 365 | kf_factor(nfft,st->factors); 366 | } 367 | return st; 368 | } 369 | 370 | 371 | void kiss_fft_stride(kiss_fft_cfg st,const kiss_fft_cpx *fin,kiss_fft_cpx *fout,int in_stride) 372 | { 373 | if (fin == fout) { 374 | //NOTE: this is not really an in-place FFT algorithm. 375 | //It just performs an out-of-place FFT into a temp buffer 376 | kiss_fft_cpx * tmpbuf = (kiss_fft_cpx*)KISS_FFT_TMP_ALLOC( sizeof(kiss_fft_cpx)*st->nfft); 377 | kf_work(tmpbuf,fin,1,in_stride, st->factors,st); 378 | memcpy(fout,tmpbuf,sizeof(kiss_fft_cpx)*st->nfft); 379 | KISS_FFT_TMP_FREE(tmpbuf); 380 | }else{ 381 | kf_work( fout, fin, 1,in_stride, st->factors,st ); 382 | } 383 | } 384 | 385 | void kiss_fft(kiss_fft_cfg cfg,const kiss_fft_cpx *fin,kiss_fft_cpx *fout) 386 | { 387 | kiss_fft_stride(cfg,fin,fout,1); 388 | } 389 | 390 | 391 | void kiss_fft_cleanup(void) 392 | { 393 | // nothing needed any more 394 | } 395 | 396 | int kiss_fft_next_fast_size(int n) 397 | { 398 | while(1) { 399 | int m=n; 400 | while ( (m%2) == 0 ) m/=2; 401 | while ( (m%3) == 0 ) m/=3; 402 | while ( (m%5) == 0 ) m/=5; 403 | if (m<=1) 404 | break; /* n is completely factorable by twos, threes, and fives */ 405 | n++; 406 | } 407 | return n; 408 | } 409 | -------------------------------------------------------------------------------- /c/kiss_fft/kiss_fft.h: -------------------------------------------------------------------------------- 1 | #ifndef KISS_FFT_H 2 | #define KISS_FFT_H 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | #ifdef __cplusplus 10 | extern "C" { 11 | #endif 12 | 13 | /* 14 | ATTENTION! 15 | If you would like a : 16 | -- a utility that will handle the caching of fft objects 17 | -- real-only (no imaginary time component ) FFT 18 | -- a multi-dimensional FFT 19 | -- a command-line utility to perform ffts 20 | -- a command-line utility to perform fast-convolution filtering 21 | 22 | Then see kfc.h kiss_fftr.h kiss_fftnd.h fftutil.c kiss_fastfir.c 23 | in the tools/ directory. 24 | */ 25 | 26 | #ifdef USE_SIMD 27 | # include 28 | # define kiss_fft_scalar __m128 29 | #define KISS_FFT_MALLOC(nbytes) _mm_malloc(nbytes,16) 30 | #define KISS_FFT_FREE _mm_free 31 | #else 32 | #define KISS_FFT_MALLOC malloc 33 | #define KISS_FFT_FREE free 34 | #endif 35 | 36 | 37 | #ifdef FIXED_POINT 38 | #include 39 | # if (FIXED_POINT == 32) 40 | # define kiss_fft_scalar int32_t 41 | # else 42 | # define kiss_fft_scalar int16_t 43 | # endif 44 | #else 45 | # ifndef kiss_fft_scalar 46 | /* default is float */ 47 | # define kiss_fft_scalar float 48 | # endif 49 | #endif 50 | 51 | typedef struct { 52 | kiss_fft_scalar r; 53 | kiss_fft_scalar i; 54 | }kiss_fft_cpx; 55 | 56 | typedef struct kiss_fft_state* kiss_fft_cfg; 57 | 58 | /* 59 | * kiss_fft_alloc 60 | * 61 | * Initialize a FFT (or IFFT) algorithm's cfg/state buffer. 62 | * 63 | * typical usage: kiss_fft_cfg mycfg=kiss_fft_alloc(1024,0,NULL,NULL); 64 | * 65 | * The return value from fft_alloc is a cfg buffer used internally 66 | * by the fft routine or NULL. 67 | * 68 | * If lenmem is NULL, then kiss_fft_alloc will allocate a cfg buffer using malloc. 69 | * The returned value should be free()d when done to avoid memory leaks. 70 | * 71 | * The state can be placed in a user supplied buffer 'mem': 72 | * If lenmem is not NULL and mem is not NULL and *lenmem is large enough, 73 | * then the function places the cfg in mem and the size used in *lenmem 74 | * and returns mem. 75 | * 76 | * If lenmem is not NULL and ( mem is NULL or *lenmem is not large enough), 77 | * then the function returns NULL and places the minimum cfg 78 | * buffer size in *lenmem. 79 | * */ 80 | 81 | kiss_fft_cfg kiss_fft_alloc(int nfft,int inverse_fft,void * mem,size_t * lenmem); 82 | 83 | /* 84 | * kiss_fft(cfg,in_out_buf) 85 | * 86 | * Perform an FFT on a complex input buffer. 87 | * for a forward FFT, 88 | * fin should be f[0] , f[1] , ... ,f[nfft-1] 89 | * fout will be F[0] , F[1] , ... ,F[nfft-1] 90 | * Note that each element is complex and can be accessed like 91 | f[k].r and f[k].i 92 | * */ 93 | void kiss_fft(kiss_fft_cfg cfg,const kiss_fft_cpx *fin,kiss_fft_cpx *fout); 94 | 95 | /* 96 | A more generic version of the above function. It reads its input from every Nth sample. 97 | * */ 98 | void kiss_fft_stride(kiss_fft_cfg cfg,const kiss_fft_cpx *fin,kiss_fft_cpx *fout,int fin_stride); 99 | 100 | /* If kiss_fft_alloc allocated a buffer, it is one contiguous 101 | buffer and can be simply free()d when no longer needed*/ 102 | #define kiss_fft_free free 103 | 104 | /* 105 | Cleans up some memory that gets managed internally. Not necessary to call, but it might clean up 106 | your compiler output to call this before you exit. 107 | */ 108 | void kiss_fft_cleanup(void); 109 | 110 | 111 | /* 112 | * Returns the smallest integer k, such that k>=n and k has only "fast" factors (2,3,5) 113 | */ 114 | int kiss_fft_next_fast_size(int n); 115 | 116 | /* for real ffts, we need an even size */ 117 | #define kiss_fftr_next_fast_size_real(n) \ 118 | (kiss_fft_next_fast_size( ((n)+1)>>1)<<1) 119 | 120 | #ifdef __cplusplus 121 | } 122 | #endif 123 | 124 | #endif 125 | -------------------------------------------------------------------------------- /c/kiss_fft/kiss_fftr.c: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2003-2004, Mark Borgerding 3 | 4 | All rights reserved. 5 | 6 | Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 7 | 8 | * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 9 | * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 10 | * Neither the author nor the names of any contributors may be used to endorse or promote products derived from this software without specific prior written permission. 11 | 12 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 13 | */ 14 | 15 | #include "kiss_fftr.h" 16 | #include "_kiss_fft_guts.h" 17 | 18 | struct kiss_fftr_state{ 19 | kiss_fft_cfg substate; 20 | kiss_fft_cpx * tmpbuf; 21 | kiss_fft_cpx * super_twiddles; 22 | #ifdef USE_SIMD 23 | void * pad; 24 | #endif 25 | }; 26 | 27 | kiss_fftr_cfg kiss_fftr_alloc(int nfft,int inverse_fft,void * mem,size_t * lenmem) 28 | { 29 | int i; 30 | kiss_fftr_cfg st = NULL; 31 | size_t subsize, memneeded; 32 | 33 | if (nfft & 1) { 34 | fprintf(stderr,"Real FFT optimization must be even.\n"); 35 | return NULL; 36 | } 37 | nfft >>= 1; 38 | 39 | kiss_fft_alloc (nfft, inverse_fft, NULL, &subsize); 40 | memneeded = sizeof(struct kiss_fftr_state) + subsize + sizeof(kiss_fft_cpx) * ( nfft * 3 / 2); 41 | 42 | if (lenmem == NULL) { 43 | st = (kiss_fftr_cfg) KISS_FFT_MALLOC (memneeded); 44 | } else { 45 | if (*lenmem >= memneeded) 46 | st = (kiss_fftr_cfg) mem; 47 | *lenmem = memneeded; 48 | } 49 | if (!st) 50 | return NULL; 51 | 52 | st->substate = (kiss_fft_cfg) (st + 1); /*just beyond kiss_fftr_state struct */ 53 | st->tmpbuf = (kiss_fft_cpx *) (((char *) st->substate) + subsize); 54 | st->super_twiddles = st->tmpbuf + nfft; 55 | kiss_fft_alloc(nfft, inverse_fft, st->substate, &subsize); 56 | 57 | for (i = 0; i < nfft/2; ++i) { 58 | double phase = 59 | -3.14159265358979323846264338327 * ((double) (i+1) / nfft + .5); 60 | if (inverse_fft) 61 | phase *= -1; 62 | kf_cexp (st->super_twiddles+i,phase); 63 | } 64 | return st; 65 | } 66 | 67 | void kiss_fftr(kiss_fftr_cfg st,const kiss_fft_scalar *timedata,kiss_fft_cpx *freqdata) 68 | { 69 | /* input buffer timedata is stored row-wise */ 70 | int k,ncfft; 71 | kiss_fft_cpx fpnk,fpk,f1k,f2k,tw,tdc; 72 | 73 | if ( st->substate->inverse) { 74 | fprintf(stderr,"kiss fft usage error: improper alloc\n"); 75 | exit(1); 76 | } 77 | 78 | ncfft = st->substate->nfft; 79 | 80 | /*perform the parallel fft of two real signals packed in real,imag*/ 81 | kiss_fft( st->substate , (const kiss_fft_cpx*)timedata, st->tmpbuf ); 82 | /* The real part of the DC element of the frequency spectrum in st->tmpbuf 83 | * contains the sum of the even-numbered elements of the input time sequence 84 | * The imag part is the sum of the odd-numbered elements 85 | * 86 | * The sum of tdc.r and tdc.i is the sum of the input time sequence. 87 | * yielding DC of input time sequence 88 | * The difference of tdc.r - tdc.i is the sum of the input (dot product) [1,-1,1,-1... 89 | * yielding Nyquist bin of input time sequence 90 | */ 91 | 92 | tdc.r = st->tmpbuf[0].r; 93 | tdc.i = st->tmpbuf[0].i; 94 | C_FIXDIV(tdc,2); 95 | CHECK_OVERFLOW_OP(tdc.r ,+, tdc.i); 96 | CHECK_OVERFLOW_OP(tdc.r ,-, tdc.i); 97 | freqdata[0].r = tdc.r + tdc.i; 98 | freqdata[ncfft].r = tdc.r - tdc.i; 99 | #ifdef USE_SIMD 100 | freqdata[ncfft].i = freqdata[0].i = _mm_set1_ps(0); 101 | #else 102 | freqdata[ncfft].i = freqdata[0].i = 0; 103 | #endif 104 | 105 | for ( k=1;k <= ncfft/2 ; ++k ) { 106 | fpk = st->tmpbuf[k]; 107 | fpnk.r = st->tmpbuf[ncfft-k].r; 108 | fpnk.i = - st->tmpbuf[ncfft-k].i; 109 | C_FIXDIV(fpk,2); 110 | C_FIXDIV(fpnk,2); 111 | 112 | C_ADD( f1k, fpk , fpnk ); 113 | C_SUB( f2k, fpk , fpnk ); 114 | C_MUL( tw , f2k , st->super_twiddles[k-1]); 115 | 116 | freqdata[k].r = HALF_OF(f1k.r + tw.r); 117 | freqdata[k].i = HALF_OF(f1k.i + tw.i); 118 | freqdata[ncfft-k].r = HALF_OF(f1k.r - tw.r); 119 | freqdata[ncfft-k].i = HALF_OF(tw.i - f1k.i); 120 | } 121 | } 122 | 123 | void kiss_fftri(kiss_fftr_cfg st,const kiss_fft_cpx *freqdata,kiss_fft_scalar *timedata) 124 | { 125 | /* input buffer timedata is stored row-wise */ 126 | int k, ncfft; 127 | 128 | if (st->substate->inverse == 0) { 129 | fprintf (stderr, "kiss fft usage error: improper alloc\n"); 130 | exit (1); 131 | } 132 | 133 | ncfft = st->substate->nfft; 134 | 135 | st->tmpbuf[0].r = freqdata[0].r + freqdata[ncfft].r; 136 | st->tmpbuf[0].i = freqdata[0].r - freqdata[ncfft].r; 137 | C_FIXDIV(st->tmpbuf[0],2); 138 | 139 | for (k = 1; k <= ncfft / 2; ++k) { 140 | kiss_fft_cpx fk, fnkc, fek, fok, tmp; 141 | fk = freqdata[k]; 142 | fnkc.r = freqdata[ncfft - k].r; 143 | fnkc.i = -freqdata[ncfft - k].i; 144 | C_FIXDIV( fk , 2 ); 145 | C_FIXDIV( fnkc , 2 ); 146 | 147 | C_ADD (fek, fk, fnkc); 148 | C_SUB (tmp, fk, fnkc); 149 | C_MUL (fok, tmp, st->super_twiddles[k-1]); 150 | C_ADD (st->tmpbuf[k], fek, fok); 151 | C_SUB (st->tmpbuf[ncfft - k], fek, fok); 152 | #ifdef USE_SIMD 153 | st->tmpbuf[ncfft - k].i *= _mm_set1_ps(-1.0); 154 | #else 155 | st->tmpbuf[ncfft - k].i *= -1; 156 | #endif 157 | } 158 | kiss_fft (st->substate, st->tmpbuf, (kiss_fft_cpx *) timedata); 159 | } 160 | -------------------------------------------------------------------------------- /c/kiss_fft/kiss_fftr.h: -------------------------------------------------------------------------------- 1 | #ifndef KISS_FTR_H 2 | #define KISS_FTR_H 3 | 4 | #include "kiss_fft.h" 5 | #ifdef __cplusplus 6 | extern "C" { 7 | #endif 8 | 9 | 10 | /* 11 | 12 | Real optimized version can save about 45% cpu time vs. complex fft of a real seq. 13 | 14 | 15 | 16 | */ 17 | 18 | typedef struct kiss_fftr_state *kiss_fftr_cfg; 19 | 20 | 21 | kiss_fftr_cfg kiss_fftr_alloc(int nfft,int inverse_fft,void * mem, size_t * lenmem); 22 | /* 23 | nfft must be even 24 | 25 | If you don't care to allocate space, use mem = lenmem = NULL 26 | */ 27 | 28 | 29 | void kiss_fftr(kiss_fftr_cfg cfg,const kiss_fft_scalar *timedata,kiss_fft_cpx *freqdata); 30 | /* 31 | input timedata has nfft scalar points 32 | output freqdata has nfft/2+1 complex points 33 | */ 34 | 35 | void kiss_fftri(kiss_fftr_cfg cfg,const kiss_fft_cpx *freqdata,kiss_fft_scalar *timedata); 36 | /* 37 | input freqdata has nfft/2+1 complex points 38 | output timedata has nfft scalar points 39 | */ 40 | 41 | #define kiss_fftr_free free 42 | 43 | #ifdef __cplusplus 44 | } 45 | #endif 46 | #endif 47 | -------------------------------------------------------------------------------- /c/rscode/rscode.c: -------------------------------------------------------------------------------- 1 | /* 2 | * qrencode - QR Code encoder 3 | * 4 | * Reed solomon encoder. This code is taken from Phil Karn's libfec then 5 | * editted and packed into a pair of .c and .h files. 6 | * 7 | * Copyright (C) 2002, 2003, 2004, 2006 Phil Karn, KA9Q 8 | * (libfec is released under the GNU Lesser General Public License.) 9 | * 10 | * Copyright (C) 2006-2011 Kentaro Fukuchi 11 | * 12 | * This library is free software; you can redistribute it and/or 13 | * modify it under the terms of the GNU Lesser General Public 14 | * License as published by the Free Software Foundation; either 15 | * version 2.1 of the License, or any later version. 16 | * 17 | * This library is distributed in the hope that it will be useful, 18 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 19 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 20 | * Lesser General Public License for more details. 21 | * 22 | * You should have received a copy of the GNU Lesser General Public 23 | * License along with this library; if not, write to the Free Software 24 | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA 25 | */ 26 | 27 | #if HAVE_CONFIG_H 28 | # include "config.h" 29 | #endif 30 | #include 31 | #include 32 | #include 33 | #ifdef HAVE_LIBPTHREAD 34 | # include 35 | #endif 36 | 37 | #ifndef NULL 38 | # define NULL ((void *)0) 39 | #endif 40 | 41 | #ifndef MIN 42 | # define MIN(a,b) ((a) < (b) ? (a) : (b)) 43 | #endif 44 | 45 | #include "rscode.h" 46 | 47 | /* Stuff specific to the 8-bit symbol version of the general purpose RS codecs 48 | * 49 | */ 50 | typedef unsigned char data_t; 51 | 52 | 53 | /** 54 | * Reed-Solomon codec control block 55 | */ 56 | struct _RS { 57 | int mm; /* Bits per symbol */ 58 | int nn; /* Symbols per block (= (1<= rs->nn) { 78 | x -= rs->nn; 79 | x = (x >> rs->mm) + (x & rs->nn); 80 | } 81 | return x; 82 | } 83 | 84 | 85 | #define MODNN(x) modnn(rs,x) 86 | 87 | #define MM (rs->mm) 88 | #define NN (rs->nn) 89 | #define ALPHA_TO (rs->alpha_to) 90 | #define INDEX_OF (rs->index_of) 91 | #define GENPOLY (rs->genpoly) 92 | #define NROOTS (rs->nroots) 93 | #define FCR (rs->fcr) 94 | #define PRIM (rs->prim) 95 | #define IPRIM (rs->iprim) 96 | #define PAD (rs->pad) 97 | #define A0 (NN) 98 | 99 | 100 | /* Initialize a Reed-Solomon codec 101 | * symsize = symbol size, bits 102 | * gfpoly = Field generator polynomial coefficients 103 | * fcr = first root of RS code generator polynomial, index form 104 | * prim = primitive element to generate polynomial roots 105 | * nroots = RS code generator polynomial degree (number of roots) 106 | * pad = padding bytes at front of shortened block 107 | */ 108 | static RS *init_rs_char(int symsize, int gfpoly, int fcr, int prim, int nroots, int pad) 109 | { 110 | RS *rs; 111 | 112 | 113 | /* Common code for intializing a Reed-Solomon control block (char or int symbols) 114 | * Copyright 2004 Phil Karn, KA9Q 115 | * May be used under the terms of the GNU Lesser General Public License (LGPL) 116 | */ 117 | //#undef NULL 118 | //#define NULL ((void *)0) 119 | 120 | int i, j, sr,root,iprim; 121 | 122 | rs = NULL; 123 | /* Check parameter ranges */ 124 | if(symsize < 0 || symsize > (int)(8*sizeof(data_t))){ 125 | goto done; 126 | } 127 | 128 | if(fcr < 0 || fcr >= (1<= (1<= (1<= ((1<mm = symsize; 142 | rs->nn = (1<pad = pad; 144 | 145 | rs->alpha_to = (data_t *)malloc(sizeof(data_t)*(rs->nn+1)); 146 | if(rs->alpha_to == NULL){ 147 | free(rs); 148 | rs = NULL; 149 | goto done; 150 | } 151 | rs->index_of = (data_t *)malloc(sizeof(data_t)*(rs->nn+1)); 152 | if(rs->index_of == NULL){ 153 | free(rs->alpha_to); 154 | free(rs); 155 | rs = NULL; 156 | goto done; 157 | } 158 | 159 | /* Generate Galois field lookup tables */ 160 | rs->index_of[0] = A0; /* log(zero) = -inf */ 161 | rs->alpha_to[A0] = 0; /* alpha**-inf = 0 */ 162 | sr = 1; 163 | for(i=0;inn;i++){ 164 | rs->index_of[sr] = i; 165 | rs->alpha_to[i] = sr; 166 | sr <<= 1; 167 | if(sr & (1<nn; 170 | } 171 | if(sr != 1){ 172 | /* field generator polynomial is not primitive! */ 173 | free(rs->alpha_to); 174 | free(rs->index_of); 175 | free(rs); 176 | rs = NULL; 177 | goto done; 178 | } 179 | 180 | /* Form RS code generator polynomial from its roots */ 181 | rs->genpoly = (data_t *)malloc(sizeof(data_t)*(nroots+1)); 182 | if(rs->genpoly == NULL){ 183 | free(rs->alpha_to); 184 | free(rs->index_of); 185 | free(rs); 186 | rs = NULL; 187 | goto done; 188 | } 189 | rs->fcr = fcr; 190 | rs->prim = prim; 191 | rs->nroots = nroots; 192 | rs->gfpoly = gfpoly; 193 | 194 | /* Find prim-th root of 1, used in decoding */ 195 | for(iprim=1;(iprim % prim) != 0;iprim += rs->nn) 196 | ; 197 | rs->iprim = iprim / prim; 198 | 199 | rs->genpoly[0] = 1; 200 | for (i = 0,root=fcr*prim; i < nroots; i++,root += prim) { 201 | rs->genpoly[i+1] = 1; 202 | 203 | /* Multiply rs->genpoly[] by @**(root + x) */ 204 | for (j = i; j > 0; j--){ 205 | if (rs->genpoly[j] != 0) 206 | rs->genpoly[j] = rs->genpoly[j-1] ^ rs->alpha_to[modnn(rs,rs->index_of[rs->genpoly[j]] + root)]; 207 | else 208 | rs->genpoly[j] = rs->genpoly[j-1]; 209 | } 210 | /* rs->genpoly[0] can never be zero */ 211 | rs->genpoly[0] = rs->alpha_to[modnn(rs,rs->index_of[rs->genpoly[0]] + root)]; 212 | } 213 | /* convert rs->genpoly[] to index form for quicker encoding */ 214 | for (i = 0; i <= nroots; i++) 215 | rs->genpoly[i] = rs->index_of[rs->genpoly[i]]; 216 | done:; 217 | 218 | return rs; 219 | } 220 | 221 | RS *init_rs(int symsize, int gfpoly, int fcr, int prim, int nroots, int pad) 222 | { 223 | RS *rs; 224 | 225 | #ifdef HAVE_LIBPTHREAD 226 | pthread_mutex_lock(&rslist_mutex); 227 | #endif 228 | for(rs = rslist; rs != NULL; rs = rs->next) { 229 | if(rs->pad != pad) continue; 230 | if(rs->nroots != nroots) continue; 231 | if(rs->mm != symsize) continue; 232 | if(rs->gfpoly != gfpoly) continue; 233 | if(rs->fcr != fcr) continue; 234 | if(rs->prim != prim) continue; 235 | 236 | goto DONE; 237 | } 238 | 239 | rs = init_rs_char(symsize, gfpoly, fcr, prim, nroots, pad); 240 | if(rs == NULL) goto DONE; 241 | rs->next = rslist; 242 | rslist = rs; 243 | 244 | DONE: 245 | #ifdef HAVE_LIBPTHREAD 246 | pthread_mutex_unlock(&rslist_mutex); 247 | #endif 248 | return rs; 249 | } 250 | 251 | 252 | void free_rs_char(RS *rs) 253 | { 254 | free(rs->alpha_to); 255 | free(rs->index_of); 256 | free(rs->genpoly); 257 | free(rs); 258 | } 259 | 260 | void free_rs_cache(void) 261 | { 262 | RS *rs, *next; 263 | 264 | #ifdef HAVE_LIBPTHREAD 265 | pthread_mutex_lock(&rslist_mutex); 266 | #endif 267 | rs = rslist; 268 | while(rs != NULL) { 269 | next = rs->next; 270 | free_rs_char(rs); 271 | rs = next; 272 | } 273 | rslist = NULL; 274 | #ifdef HAVE_LIBPTHREAD 275 | pthread_mutex_unlock(&rslist_mutex); 276 | #endif 277 | } 278 | 279 | /* The guts of the Reed-Solomon encoder, meant to be #included 280 | * into a function body with the following typedefs, macros and variables supplied 281 | * according to the code parameters: 282 | 283 | * data_t - a typedef for the data symbol 284 | * data_t data[] - array of NN-NROOTS-PAD and type data_t to be encoded 285 | * data_t parity[] - an array of NROOTS and type data_t to be written with parity symbols 286 | * NROOTS - the number of roots in the RS code generator polynomial, 287 | * which is the same as the number of parity symbols in a block. 288 | Integer variable or literal. 289 | * 290 | * NN - the total number of symbols in a RS block. Integer variable or literal. 291 | * PAD - the number of pad symbols in a block. Integer variable or literal. 292 | * ALPHA_TO - The address of an array of NN elements to convert Galois field 293 | * elements in index (log) form to polynomial form. Read only. 294 | * INDEX_OF - The address of an array of NN elements to convert Galois field 295 | * elements in polynomial form to index (log) form. Read only. 296 | * MODNN - a function to reduce its argument modulo NN. May be inline or a macro. 297 | * GENPOLY - an array of NROOTS+1 elements containing the generator polynomial in index form 298 | 299 | * The memset() and memmove() functions are used. The appropriate header 300 | * file declaring these functions (usually ) must be included by the calling 301 | * program. 302 | 303 | * Copyright 2004, Phil Karn, KA9Q 304 | * May be used under the terms of the GNU Lesser General Public License (LGPL) 305 | */ 306 | 307 | #undef A0 308 | #define A0 (NN) /* Special reserved value encoding zero in index form */ 309 | 310 | void encode_rs_char(RS *rs, const data_t *data, data_t *parity) 311 | { 312 | int i, j; 313 | data_t feedback; 314 | 315 | memset(parity,0,NROOTS*sizeof(data_t)); 316 | 317 | for(i=0;i 0) { 392 | 393 | /* Init lambda to be the erasure locator polynomial */ 394 | lambda[1] = ALPHA_TO[MODNN(PRIM*(NN-1-eras_pos[0]))]; 395 | 396 | for (i = 1; i < no_eras; i++) { 397 | 398 | u = MODNN(PRIM*(NN-1-eras_pos[i])); 399 | 400 | for (j = i+1; j > 0; j--) { 401 | 402 | tmp = INDEX_OF[lambda[j - 1]]; 403 | 404 | if(tmp != A0) 405 | lambda[j] ^= ALPHA_TO[MODNN(u + tmp)]; 406 | } 407 | } 408 | 409 | #if DEBUG >= 1 410 | /* Test code that verifies the erasure locator polynomial just constructed 411 | Needed only for decoder debugging. */ 412 | 413 | /* find roots of the erasure location polynomial */ 414 | for(i=1;i<=no_eras;i++) 415 | reg[i] = INDEX_OF[lambda[i]]; 416 | 417 | count = 0; 418 | for (i = 1,k=IPRIM-1; i <= NN; i++,k = MODNN(k+IPRIM)) { 419 | q = 1; 420 | for (j = 1; j <= no_eras; j++) 421 | if (reg[j] != A0) { 422 | reg[j] = MODNN(reg[j] + j); 423 | q ^= ALPHA_TO[reg[j]]; 424 | } 425 | if (q != 0) 426 | continue; 427 | /* store root and error location number indices */ 428 | root[count] = i; 429 | loc[count] = k; 430 | count++; 431 | } 432 | if (count != no_eras) { 433 | printf("count = %d no_eras = %d\n lambda(x) is WRONG\n",count,no_eras); 434 | count = -1; 435 | goto finish; 436 | } 437 | #if DEBUG >= 2 438 | printf("\n Erasure positions as determined by roots of Eras Loc Poly:\n"); 439 | for (i = 0; i < count; i++) 440 | printf("%d ", loc[i]); 441 | printf("\n"); 442 | #endif 443 | #endif 444 | } 445 | for(i=0;i 0; j--){ 506 | if (reg[j] != A0) { 507 | reg[j] = MODNN(reg[j] + j); 508 | q ^= ALPHA_TO[reg[j]]; 509 | } 510 | } 511 | if (q != 0) 512 | continue; /* Not a root */ 513 | /* store root (index-form) and error location number */ 514 | #if DEBUG>=2 515 | printf("count %d root %d loc %d\n",count,i,k); 516 | #endif 517 | root[count] = i; 518 | loc[count] = k; 519 | /* If we've already found max possible roots, 520 | * abort the search to save time 521 | */ 522 | if(++count == deg_lambda) 523 | break; 524 | } 525 | if (deg_lambda != count) { 526 | /* 527 | * deg(lambda) unequal to number of roots => uncorrectable 528 | * error detected 529 | */ 530 | count = -1; 531 | goto finish; 532 | } 533 | /* 534 | * Compute err+eras evaluator poly omega(x) = s(x)*lambda(x) (modulo 535 | * x**NROOTS). in index form. Also find deg(omega). 536 | */ 537 | deg_omega = deg_lambda-1; 538 | for (i = 0; i <= deg_omega;i++){ 539 | tmp = 0; 540 | for(j=i;j >= 0; j--){ 541 | if ((s[i - j] != A0) && (lambda[j] != A0)) 542 | tmp ^= ALPHA_TO[MODNN(s[i - j] + lambda[j])]; 543 | } 544 | omega[i] = INDEX_OF[tmp]; 545 | } 546 | 547 | /* 548 | * Compute error values in poly-form. num1 = omega(inv(X(l))), num2 = 549 | * inv(X(l))**(FCR-1) and den = lambda_pr(inv(X(l))) all in poly-form 550 | */ 551 | for (j = count-1; j >=0; j--) { 552 | num1 = 0; 553 | for (i = deg_omega; i >= 0; i--) { 554 | if (omega[i] != A0) 555 | num1 ^= ALPHA_TO[MODNN(omega[i] + i * root[j])]; 556 | } 557 | num2 = ALPHA_TO[MODNN(root[j] * (FCR - 1) + NN)]; 558 | den = 0; 559 | 560 | /* lambda[i+1] for i even is the formal derivative lambda_pr of lambda[i] */ 561 | for (i = MIN(deg_lambda,NROOTS-1) & ~1; i >= 0; i -=2) { 562 | if(lambda[i+1] != A0) 563 | den ^= ALPHA_TO[MODNN(lambda[i+1] + i * root[j])]; 564 | } 565 | #if DEBUG >= 1 566 | if (den == 0) { 567 | printf("\n ERROR: denominator = 0\n"); 568 | count = -1; 569 | goto finish; 570 | } 571 | #endif 572 | /* Apply error to data */ 573 | if (num1 != 0 && loc[j] >= PAD) { 574 | data[loc[j]-PAD] ^= ALPHA_TO[MODNN(INDEX_OF[num1] + INDEX_OF[num2] + NN - INDEX_OF[den])]; 575 | } 576 | } 577 | finish: 578 | if(eras_pos != NULL){ 579 | for(i=0;i 11 | * 12 | * This library is free software; you can redistribute it and/or 13 | * modify it under the terms of the GNU Lesser General Public 14 | * License as published by the Free Software Foundation; either 15 | * version 2.1 of the License, or any later version. 16 | * 17 | * This library is distributed in the hope that it will be useful, 18 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 19 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 20 | * Lesser General Public License for more details. 21 | * 22 | * You should have received a copy of the GNU Lesser General Public 23 | * License along with this library; if not, write to the Free Software 24 | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA 25 | */ 26 | 27 | #ifndef __RSCODE_H__ 28 | #define __RSCODE_H__ 29 | 30 | #define RS_SYMSIZE 5 31 | #define RS_GFPOLY 0x25 32 | #define RS_FCR 1 33 | #define RS_PRIM 1 34 | #define RS_NROOTS 8 35 | #define RS_DATA_LEN 10 36 | #define RS_TOTAL_LEN (RS_DATA_LEN + RS_NROOTS) 37 | #define RS_PAD ((1< @一个开发者 4 | */ 5 | 6 | (function() { 7 | var baseFrequency, beepLength, char, characters, context, freq, freqCodes, frequencies, i, semitone, _i, _len; 8 | 9 | window.AudioContext || (window.AudioContext = window.webkitAudioContext || window.mozAudioContext || window.msAudioContext || window.oAudioContext); 10 | 11 | semitone = 1.05946311; 12 | 13 | baseFrequency = 1760; 14 | 15 | beepLength = 87.2; 16 | 17 | characters = '0123456789abcdefghijklmnopqrstuv'; 18 | 19 | freqCodes = {}; 20 | 21 | frequencies = []; 22 | 23 | for (i = _i = 0, _len = characters.length; _i < _len; i = ++_i) { 24 | 25 | char = characters[i]; 26 | freq = +(baseFrequency * Math.pow(semitone, i)).toFixed(3); 27 | freqCodes[char] = freq; 28 | frequencies[i] = freq; 29 | } 30 | 31 | context = new AudioContext(); 32 | 33 | window.chirp = function(message, ecc) { 34 | var chirp, front_door, gainNode, now, oscillator, _j, _len1; 35 | front_door = 'hj'; 36 | chirp = front_door + message + ecc; 37 | oscillator = context.createOscillator(); 38 | oscillator.type = 0; 39 | gainNode = context.createGainNode(); 40 | gainNode.gain.value = 0.6; 41 | oscillator.connect(gainNode); 42 | gainNode.connect(context.destination); 43 | now = context.currentTime; 44 | for (i = _j = 0, _len1 = chirp.length; _j < _len1; i = ++_j) { 45 | char = chirp[i]; 46 | oscillator.frequency.setValueAtTime(freqCodes[char], now + (beepLength / 1000 * i)); 47 | } 48 | oscillator.start(now); 49 | return oscillator.stop(now + (beepLength / 1000 * (chirp.length + 1))); 50 | }; 51 | 52 | }).call(this); 53 | -------------------------------------------------------------------------------- /javascript/example.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | -------------------------------------------------------------------------------- /objc/PCMRender/PCMRender.h: -------------------------------------------------------------------------------- 1 | // 2 | // PCMRender.h 3 | // PlayPCM 4 | // 5 | // Created by hanchao on 13-11-22. 6 | // Copyright (c) 2013年 hanchao. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface PCMRender : NSObject 12 | 13 | + (NSData *)renderChirpData:(NSString *)serializeStr; 14 | 15 | @end 16 | -------------------------------------------------------------------------------- /objc/PCMRender/PCMRender.m: -------------------------------------------------------------------------------- 1 | // 2 | // PCMRender.m 3 | // PlayPCM 4 | // 5 | // Created by hanchao on 13-11-22. 6 | // Copyright (c) 2013年 hanchao. All rights reserved. 7 | // 8 | 9 | #import "PCMRender.h" 10 | 11 | 12 | #define SAMPLE_RATE 44100 //采样频率 13 | #define BB_SEMITONE 1.05946311 14 | #define BB_BASEFREQUENCY 1760 15 | #define BB_CHARACTERS "0123456789abcdefghijklmnopqrstuv" 16 | //#define BB_THRESHOLD 16 17 | #define BITS_PER_SAMPLE 16 18 | #define BB_HEADER_0 17 19 | #define BB_HEADER_1 19 20 | #define DURATION 0.0872 // seconds 0.1744// 21 | #define MAX_VOLUME 0.5 22 | static float frequencies[32]; 23 | 24 | @implementation PCMRender 25 | 26 | #pragma mark - 27 | 28 | //wav文件格式详见:http://www-mmsp.ece.mcgill.ca/Documents../AudioFormats/WAVE/WAVE.html 29 | //wav头的结构如下所示: 30 | typedef struct { 31 | char fccID[4];//"RIFF"标志 32 | unsigned long dwSize;//文件长度 33 | char fccType[4];//"WAVE"标志 34 | }HEADER; 35 | 36 | typedef struct { 37 | char fccID[4];//"fmt"标志 38 | unsigned long dwSize;//Chunk size: 16 39 | unsigned short wFormatTag;// 格式类别 40 | unsigned short wChannels;//声道数 41 | unsigned long dwSamplesPerSec;//采样频率 42 | unsigned long dwAvgBytesPerSec;//位速 sample_rate * 2 * chans//为什么乘2呢?因为此时是16位的PCM数据,一个采样占两个byte。 43 | unsigned short wBlockAlign;//一个采样多声道数据块大小 44 | unsigned short uiBitsPerSample;//一个采样占的bit数 45 | }FMT; 46 | 47 | typedef struct { 48 | char fccID[4]; //数据标记符"data" 49 | unsigned long dwSize;//语音数据的长度,比文件长度小36 50 | }DATA; 51 | 52 | //添加wav头信息 53 | int addWAVHeader(unsigned char *buffer, int sample_rate, int bytesPerSample, int channels, long dataByteSize) 54 | { 55 | //以下是为了建立.wav头而准备的变量 56 | HEADER pcmHEADER; 57 | FMT pcmFMT; 58 | DATA pcmDATA; 59 | 60 | //以下是创建wav头的HEADER;但.dwsize未定,因为不知道Data的长度。 61 | strcpy(pcmHEADER.fccID,"RIFF"); 62 | pcmHEADER.dwSize=44+dataByteSize; //根据pcmDATA.dwsize得出pcmHEADER.dwsize的值 63 | memcpy(pcmHEADER.fccType, "WAVE", sizeof(char)*4); 64 | 65 | memcpy(buffer, &pcmHEADER, sizeof(pcmHEADER)); 66 | 67 | //以上是创建wav头的HEADER; 68 | 69 | //以下是创建wav头的FMT; 70 | strcpy(pcmFMT.fccID,"fmt "); 71 | pcmFMT.dwSize=16; 72 | pcmFMT.wFormatTag=3; 73 | pcmFMT.wChannels=channels; 74 | pcmFMT.dwSamplesPerSec=sample_rate; 75 | pcmFMT.dwAvgBytesPerSec=sample_rate * bytesPerSample * channels;//F * M * Nc 76 | pcmFMT.wBlockAlign=bytesPerSample * channels;//M * Nc 77 | pcmFMT.uiBitsPerSample=ceil(8 * bytesPerSample); 78 | 79 | memcpy(buffer+sizeof(pcmHEADER), &pcmFMT, sizeof (pcmFMT)); 80 | //以上是创建wav头的FMT; 81 | 82 | //以下是创建wav头的DATA; 但由于DATA.dwsize未知所以不能写入.wav文件 83 | strcpy(pcmDATA.fccID,"data"); 84 | pcmDATA.dwSize=dataByteSize; //给pcmDATA.dwsize 0以便于下面给它赋值 85 | 86 | memcpy(buffer+sizeof(pcmHEADER)+sizeof(pcmFMT), &pcmDATA, sizeof(pcmDATA)); 87 | 88 | return 0; 89 | } 90 | 91 | 92 | #pragma mark - 数字转频率 93 | void freq_init() { 94 | 95 | static int flag = 0; 96 | 97 | if (flag) { 98 | 99 | return; 100 | } 101 | 102 | int i, len; 103 | 104 | for (i=0, len = strlen(BB_CHARACTERS); i=0 && n<32) { 119 | 120 | *f = (unsigned int)floor(frequencies[n]); 121 | 122 | return 0; 123 | } 124 | 125 | return -1; 126 | } 127 | 128 | int char_to_num(char c, unsigned int *n) { 129 | 130 | if (n == NULL) return -1; 131 | 132 | *n = 0; 133 | 134 | if (c>=48 && c<=57) { 135 | 136 | *n = c - 48; 137 | 138 | return 0; 139 | 140 | } else if (c>=97 && c<=118) { 141 | 142 | *n = c - 87; 143 | 144 | return 0; 145 | } 146 | 147 | return -1; 148 | } 149 | 150 | int char_to_freq(char c, unsigned int *f) { 151 | 152 | unsigned int n; 153 | 154 | if (f != NULL && char_to_num(c, &n) == 0) { 155 | 156 | unsigned int ff; 157 | 158 | if (num_to_freq(n, &ff) == 0) { 159 | 160 | *f = ff; 161 | return 0; 162 | } 163 | } 164 | 165 | return -1; 166 | } 167 | 168 | 169 | void makeChirp(Float32 buffer[],int bufferLength,unsigned int freqArray[], int freqArrayLength, double duration_secs, 170 | long sample_rate, int bits_persample) { 171 | 172 | double theta = 0; 173 | int idx = 0; 174 | for (int i=0; i 2.0 * M_PI) 188 | { 189 | theta -= 2.0 * M_PI; 190 | } 191 | } 192 | 193 | } 194 | } 195 | 196 | 197 | + (NSData *)renderChirpData:(NSString *)serializeStr { 198 | 199 | if (serializeStr && serializeStr.length > 0) { 200 | 201 | /* 202 | * 序列化字符串转频率 203 | */ 204 | unichar *charArray = malloc(sizeof(unichar)*serializeStr.length); 205 | 206 | [serializeStr getCharacters:charArray]; 207 | 208 | unsigned freqArray[serializeStr.length+2];//起始音17,19 209 | //memset(freqArray, 0, sizeof(unsigned) * (serializeStr.length+2)); 210 | 211 | char_to_freq('h', freqArray); 212 | char_to_freq('j', freqArray+1); 213 | 214 | //freqArray[0] = 123; 215 | //freqArray[1] = 321; 216 | 217 | for (int i=0; i 12 | * 13 | * PHP QR Code is distributed under LGPL 3 14 | * Copyright (C) 2010 Dominik Dzienia 15 | * 16 | * This library is free software; you can redistribute it and/or 17 | * modify it under the terms of the GNU Lesser General Public 18 | * License as published by the Free Software Foundation; either 19 | * version 3 of the License, or any later version. 20 | * 21 | * This library is distributed in the hope that it will be useful, 22 | * but WITHOUT ANY WARRANTY; without even the implied warranty of 23 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 24 | * Lesser General Public License for more details. 25 | * 26 | * You should have received a copy of the GNU Lesser General Public 27 | * License along with this library; if not, write to the Free Software 28 | * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA 29 | */ 30 | 31 | class QRrsItem { 32 | 33 | public $mm; // Bits per symbol 34 | public $nn; // Symbols per block (= (1<= $this->nn) { 49 | $x -= $this->nn; 50 | $x = ($x >> $this->mm) + ($x & $this->nn); 51 | } 52 | 53 | return $x; 54 | } 55 | 56 | //---------------------------------------------------------------------- 57 | public static function init_rs_char($symsize, $gfpoly, $fcr, $prim, $nroots, $pad) 58 | { 59 | // Common code for intializing a Reed-Solomon control block (char or int symbols) 60 | // Copyright 2004 Phil Karn, KA9Q 61 | // May be used under the terms of the GNU Lesser General Public License (LGPL) 62 | 63 | $rs = null; 64 | 65 | // Check parameter ranges 66 | if($symsize < 0 || $symsize > 8) return $rs; 67 | if($fcr < 0 || $fcr >= (1<<$symsize)) return $rs; 68 | if($prim <= 0 || $prim >= (1<<$symsize)) return $rs; 69 | if($nroots < 0 || $nroots >= (1<<$symsize)) return $rs; // Can't have more roots than symbol values! 70 | if($pad < 0 || $pad >= ((1<<$symsize) -1 - $nroots)) return $rs; // Too much padding 71 | 72 | $rs = new QRrsItem(); 73 | $rs->mm = $symsize; 74 | $rs->nn = (1<<$symsize)-1; 75 | $rs->pad = $pad; 76 | 77 | $rs->alpha_to = array_fill(0, $rs->nn+1, 0); 78 | $rs->index_of = array_fill(0, $rs->nn+1, 0); 79 | 80 | // PHP style macro replacement ;) 81 | $NN =& $rs->nn; 82 | $A0 =& $NN; 83 | 84 | // Generate Galois field lookup tables 85 | $rs->index_of[0] = $A0; // log(zero) = -inf 86 | $rs->alpha_to[$A0] = 0; // alpha**-inf = 0 87 | $sr = 1; 88 | 89 | for($i=0; $i<$rs->nn; $i++) { 90 | $rs->index_of[$sr] = $i; 91 | $rs->alpha_to[$i] = $sr; 92 | $sr <<= 1; 93 | if($sr & (1<<$symsize)) { 94 | $sr ^= $gfpoly; 95 | } 96 | $sr &= $rs->nn; 97 | } 98 | 99 | if($sr != 1){ 100 | // field generator polynomial is not primitive! 101 | $rs = NULL; 102 | return $rs; 103 | } 104 | 105 | /* Form RS code generator polynomial from its roots */ 106 | $rs->genpoly = array_fill(0, $nroots+1, 0); 107 | 108 | $rs->fcr = $fcr; 109 | $rs->prim = $prim; 110 | $rs->nroots = $nroots; 111 | $rs->gfpoly = $gfpoly; 112 | 113 | /* Find prim-th root of 1, used in decoding */ 114 | for($iprim=1;($iprim % $prim) != 0;$iprim += $rs->nn) 115 | ; // intentional empty-body loop! 116 | 117 | $rs->iprim = (int)($iprim / $prim); 118 | $rs->genpoly[0] = 1; 119 | 120 | for ($i = 0,$root=$fcr*$prim; $i < $nroots; $i++, $root += $prim) { 121 | $rs->genpoly[$i+1] = 1; 122 | 123 | // Multiply rs->genpoly[] by @**(root + x) 124 | for ($j = $i; $j > 0; $j--) { 125 | if ($rs->genpoly[$j] != 0) { 126 | $rs->genpoly[$j] = $rs->genpoly[$j-1] ^ $rs->alpha_to[$rs->modnn($rs->index_of[$rs->genpoly[$j]] + $root)]; 127 | } else { 128 | $rs->genpoly[$j] = $rs->genpoly[$j-1]; 129 | } 130 | } 131 | // rs->genpoly[0] can never be zero 132 | $rs->genpoly[0] = $rs->alpha_to[$rs->modnn($rs->index_of[$rs->genpoly[0]] + $root)]; 133 | } 134 | 135 | // convert rs->genpoly[] to index form for quicker encoding 136 | for ($i = 0; $i <= $nroots; $i++) 137 | $rs->genpoly[$i] = $rs->index_of[$rs->genpoly[$i]]; 138 | 139 | return $rs; 140 | } 141 | 142 | //---------------------------------------------------------------------- 143 | public function encode_rs_char($data, &$parity) 144 | { 145 | $MM =& $this->mm; 146 | $NN =& $this->nn; 147 | $ALPHA_TO =& $this->alpha_to; 148 | $INDEX_OF =& $this->index_of; 149 | $GENPOLY =& $this->genpoly; 150 | $NROOTS =& $this->nroots; 151 | $FCR =& $this->fcr; 152 | $PRIM =& $this->prim; 153 | $IPRIM =& $this->iprim; 154 | $PAD =& $this->pad; 155 | $A0 =& $NN; 156 | 157 | $parity = array_fill(0, $NROOTS, 0); 158 | 159 | for($i=0; $i< ($NN-$NROOTS-$PAD); $i++) { 160 | 161 | $feedback = $INDEX_OF[$data[$i] ^ $parity[0]]; 162 | if($feedback != $A0) { 163 | // feedback term is non-zero 164 | 165 | // This line is unnecessary when GENPOLY[NROOTS] is unity, as it must 166 | // always be for the polynomials constructed by init_rs() 167 | $feedback = $this->modnn($NN - $GENPOLY[$NROOTS] + $feedback); 168 | 169 | for($j=1;$j<$NROOTS;$j++) { 170 | $parity[$j] ^= $ALPHA_TO[$this->modnn($feedback + $GENPOLY[$NROOTS-$j])]; 171 | } 172 | } 173 | 174 | // Shift 175 | array_shift($parity); 176 | if($feedback != $A0) { 177 | array_push($parity, $ALPHA_TO[$this->modnn($feedback + $GENPOLY[0])]); 178 | } else { 179 | array_push($parity, 0); 180 | } 181 | } 182 | } 183 | } 184 | 185 | //########################################################################## 186 | 187 | class QRrs { 188 | 189 | public static $items = array(); 190 | 191 | //---------------------------------------------------------------------- 192 | public static function init_rs($symsize, $gfpoly, $fcr, $prim, $nroots, $pad) 193 | { 194 | foreach(self::$items as $rs) { 195 | if($rs->pad != $pad) continue; 196 | if($rs->nroots != $nroots) continue; 197 | if($rs->mm != $symsize) continue; 198 | if($rs->gfpoly != $gfpoly) continue; 199 | if($rs->fcr != $fcr) continue; 200 | if($rs->prim != $prim) continue; 201 | 202 | return $rs; 203 | } 204 | 205 | $rs = QRrsItem::init_rs_char($symsize, $gfpoly, $fcr, $prim, $nroots, $pad); 206 | array_unshift(self::$items, $rs); 207 | 208 | return $rs; 209 | } 210 | } -------------------------------------------------------------------------------- /php/wave/WavForge.php: -------------------------------------------------------------------------------- 1 | 5 | * 6 | * Redistribution and use in source and binary forms, with or without 7 | * modification, are permitted provided that the following conditions are 8 | * met: 9 | * 10 | * Redistributions of source code must retain the above copyright notice, 11 | * this list of conditions and the following disclaimer. 12 | * 13 | * Redistributions in binary form must reproduce the above copyright 14 | * notice, this list of conditions and the following disclaimer in the 15 | * documentation and/or other materials provided with the distribution. 16 | * 17 | * Neither the name of sk89q nor the names of its contributors may be 18 | * used to endorse or promote products derived from this software 19 | * without specific prior written permission. 20 | * 21 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 22 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 23 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 24 | * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 25 | * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 26 | * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 27 | * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 28 | * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 29 | * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 30 | * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 31 | * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 32 | */ 33 | 34 | /** 35 | * @package com.therisenrealm.sound.sampled 36 | */ 37 | 38 | // PHPNS: namespace com\therisenrealm\sound\sampled 39 | 40 | /** 41 | * This class generates PCM WAV files and can also synthesize some 42 | * waveforms. 43 | * 44 | * This is largely a proof of concept. It runs too slowly to be of much 45 | * use. 46 | * 47 | * @package com.therisenrealm.sound.sampled 48 | */ 49 | class WavForge 50 | { 51 | /** 52 | * Store the number of channels to be generated. 53 | * 54 | * @var int 55 | */ 56 | private $channels = 1; 57 | /** 58 | * The sample rate at which the sample_count will be generated at. 59 | * 60 | * @var int 61 | */ 62 | private $sample_rate = 44100; 63 | /** 64 | * Maximum number of bits per sample. 65 | * 66 | * @var unknown_type 67 | */ 68 | private $bits_per_sample = 16; 69 | 70 | /** 71 | * Store the number of samples that have been generated. 72 | * 73 | * @var int 74 | */ 75 | private $sample_count = 0; 76 | /** 77 | * Contains the samples. 78 | * 79 | * @var string 80 | */ 81 | private $output; 82 | 83 | /** 84 | * Constructs the object. The number of channels, the sample rate, and 85 | * the bits per sample can be specified. 86 | * 87 | * @param int $channels 88 | * @param int $sample_rate 89 | * @param int $bits_per_sample 90 | */ 91 | public function __construct($channels = 2, $sample_rate = 44100, 92 | $bits_per_sample = 16) 93 | { 94 | $this->channels = $channels; 95 | $this->sample_rate = $sample_rate; 96 | $this->bits_per_sample = $bits_per_sample; 97 | } 98 | 99 | /** 100 | * Get the number of channels specified. 101 | * 102 | * @return int 103 | */ 104 | public function getChannels() 105 | { 106 | return $this->channels; 107 | } 108 | 109 | /** 110 | * Specify the number of channels. Once audio data has been generated, 111 | * the number of channels should not be changed. 112 | * 113 | * @param int $channels 114 | */ 115 | public function setChannels($channels) 116 | { 117 | $this->channels = $channels; 118 | } 119 | 120 | /** 121 | * Get the sample rate specified. 122 | * 123 | * @return int 124 | */ 125 | public function getSampleRate() 126 | { 127 | return $this->sample_rate; 128 | } 129 | 130 | /** 131 | * Specify the sample rate. Once audio data has been generated, the 132 | * sample rate should not be changed. 133 | * 134 | * @param int $sample_rate 135 | */ 136 | public function setSampleRate($sample_rate) 137 | { 138 | $this->sample_rate = $sample_rate; 139 | } 140 | 141 | /** 142 | * Get the bits per sample specified. 143 | * 144 | * @return int 145 | */ 146 | public function getBitsPerSample() 147 | { 148 | return $this->bits_per_sample; 149 | } 150 | 151 | /** 152 | * Specify the bits per sample. Once audio data has been generated, do 153 | * not change the bits per sample. 154 | * 155 | * @param int $bits_per_sample 156 | */ 157 | public function setBitsPerSample($bits_per_sample) 158 | { 159 | $this->bits_per_sample = $bits_per_sample; 160 | } 161 | 162 | /** 163 | * Get the count of samples. 164 | * 165 | */ 166 | public function getSampleCount() 167 | { 168 | return $this->sample_count; 169 | } 170 | 171 | /** 172 | * Get the raw sample data. 173 | * 174 | * @return string 175 | */ 176 | public function getData() 177 | { 178 | return $this->output; 179 | } 180 | 181 | /** 182 | * Add samples. 183 | * 184 | * @param string $data 185 | * @param int $sample_count 186 | */ 187 | public function addSamples($data, $sample_count) 188 | { 189 | $this->data .= $data; 190 | $this->sample_count += $sample_count; 191 | } 192 | 193 | /** 194 | * Gets the WAV file with the data and header. 195 | * 196 | * @return string 197 | */ 198 | public function getWAVData() 199 | { 200 | return $this->getWAVHeader() . $this->output; 201 | } 202 | 203 | /** 204 | * Generate the WAV header. 205 | * 206 | * @return string 207 | */ 208 | private function getWAVHeader() 209 | { 210 | $subchunk_2_size = $this->sample_count * $this->channels * 211 | $this->bits_per_sample / 8; 212 | 213 | $header .= pack('N', 0x52494646); // ChunkID [0,4] RIFF 214 | $header .= pack('V', $subchunk_2_size + 36); // ChunkSize [0,4] 215 | $header .= pack('N', 0x57415645); // Format [8,4] WAVE 216 | $header .= pack('N', 0x666d7420); // Subchunk1ID [12,4] fmt 217 | $header .= pack('V', 16); // Subchunk1Size [16,4] 16 for PCM 218 | $header .= pack('v', 1); // AudioFormat [20,2] 1 for PCM 219 | $header .= pack('v', $this->channels); // NumChannels [22,2] 1 for mono, 2 for stereo 220 | $header .= pack('V', $this->sample_rate); // SampleRate [24,4] 221 | $header .= pack('V', $this->sample_rate * $this->channels * 222 | $this->bits_per_sample / 8); // ByteRate [28,4] SampleRate * NumChannels * BitsPerSample / 8 223 | $header .= pack('v', $this->channels * $this->bits_per_sample / 8); // BlockAlign [32,2] NumChannels * BitsPerSample / 8 224 | 225 | $header .= pack('v', $this->bits_per_sample); // BitsPerSample [34,2] 226 | $header .= pack('N', 0x64617461); // Subchunk1ID [36,4] data 227 | $header .= pack('V', $subchunk_2_size); // Subchunk2Size [40,4] 228 | 229 | return $header; 230 | } 231 | 232 | /** 233 | * Encodes a sample. 234 | * 235 | * @throws OutOfRangeException Overflow 236 | * @return string 237 | */ 238 | public function encodeSample($num) 239 | { 240 | $max = pow(2, $this->bits_per_sample); 241 | if ($num < 0) { 242 | $num += $max; 243 | } 244 | if ($num >= $max) { 245 | throw new OutOfRangeException("Overflow ({$num} won't fit into an {$this->bits_per_sample}-bit integer)"); 246 | } 247 | $b = array(); 248 | while ($num > 0) { 249 | $b[] = chr($num % 256); 250 | $num = floor($num / 256); 251 | } 252 | for ($i = 0; $i < -(-$this->bits_per_sample >> 3) - count($b); $i++) { 253 | $b[] = chr(0); 254 | } 255 | return implode('', $b); 256 | } 257 | 258 | /** 259 | * Generate a sine waveform. 260 | * 261 | * @param float $frequency 262 | * @param float $volume Percentage in volume (.5 for 50%) 263 | * @param float $seconds 264 | * @throws OutOfRangeException Volume out of range 265 | */ 266 | public function synthesizeSine($frequency, $volume, $seconds) 267 | { 268 | $b = pow(2, $this->bits_per_sample) / 2; 269 | for ($i = 0; $i < $seconds * $this->sample_rate; $i++) { 270 | // Add a sample for each channel 271 | $this->output .= str_repeat( 272 | $this->encodeSample( 273 | $volume * $b * // <- amplitude 274 | sin(2 * M_PI * $i * $frequency / $this->sample_rate) 275 | ), 276 | $this->channels); 277 | $this->sample_count++; 278 | } 279 | } 280 | 281 | /** 282 | * Generate a sine waveform. 283 | * 284 | * @param float $frequency 285 | * @param float $volume Percentage in volume (.5 for 50%) 286 | * @param float $seconds 287 | * @throws OutOfRangeException Volume out of range 288 | */ 289 | public function synthesizeSineMulti($frequency_array, $volume_max, $seconds) 290 | { 291 | $b = pow(2, $this->bits_per_sample) / 2; 292 | 293 | $count = count($frequency_array); 294 | 295 | for ($j = 0; $j < $count; $j++) { 296 | 297 | $frequency = $frequency_array[$j]; 298 | 299 | for ($i = 0; $i < $seconds * $this->sample_rate; $i++) { 300 | 301 | $n = $seconds * $this->sample_rate; 302 | 303 | /* 304 | if ($i <= ($n / 2)) { 305 | 306 | $v = $volume * 2 * ($i / $n); 307 | 308 | } else { 309 | 310 | $v = $volume * 2 * (1 - ($i / $n)); 311 | } 312 | */ 313 | 314 | $volume = $volume_max * sqrt( 1.0 - (pow($i - ($n / 2), 2) / pow(($n / 2), 2)) ); 315 | 316 | /* 317 | $a1 = $n * 0.1; 318 | $a2 = $n * 0.9; 319 | 320 | if ($i < $a1) { 321 | 322 | $v = $volume / $a1; 323 | 324 | } else if ($i >= $a1 && $i <= $a2) { 325 | 326 | $v = $volume; 327 | 328 | } else { 329 | 330 | $v = ($n - $i) * $volume / ($n - $a2); 331 | } 332 | */ 333 | 334 | // Add a sample for each channel 335 | $this->output .= str_repeat( 336 | $this->encodeSample( 337 | $volume * $b * // <- amplitude 338 | sin(2 * M_PI * $i * $frequency / $this->sample_rate) 339 | ), 340 | $this->channels); 341 | $this->sample_count++; 342 | } 343 | } 344 | } 345 | 346 | /** 347 | * Generate a sawtooth waveform. 348 | * 349 | * @param float $frequency 350 | * @param float $volume Percentage in volume (.5 for 50%) 351 | * @param float $seconds 352 | * @throws OutOfRangeException Volume out of range 353 | */ 354 | public function synthesizeSawtooth($frequency, $volume, $seconds) 355 | { 356 | $b = pow(2, $this->bits_per_sample) / 2; 357 | for ($i = 0; $i < $seconds * $this->sample_rate; $i++) { 358 | // Add a sample for each channel 359 | $this->output .= str_repeat( 360 | $this->encodeSample( 361 | $volume * $b * // <- amplitude 362 | ($i * $frequency / $this->sample_rate - 363 | floor($i * $frequency / $this->sample_rate)) 364 | ), 365 | $this->channels); 366 | $this->sample_count++; 367 | } 368 | } 369 | 370 | /** 371 | * Generate noise. 372 | * 373 | * @param float $volume Percentage in volume (.5 for 50%) 374 | * @param float $seconds 375 | * @throws OutOfRangeException Volume out of range 376 | */ 377 | public function synthesizeNoise($volume, $seconds) 378 | { 379 | $b = pow(2, $this->bits_per_sample) / 2; 380 | for ($i = 0; $i < $seconds * $this->sample_rate; $i++) { 381 | // Add a sample for each channel 382 | $this->output .= str_repeat( 383 | $this->encodeSample( 384 | rand(0, $volume * $b) 385 | ), 386 | $this->channels); 387 | $this->sample_count++; 388 | } 389 | } 390 | } --------------------------------------------------------------------------------