You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 

295 lines
6.7 KiB

  1. /*
  2. * Aptdec
  3. * Copyright (c) 2004 by Thierry Leconte (F4DWV)
  4. *
  5. * $Id$
  6. *
  7. * This library is free software; you can redistribute it and/or modify
  8. * it under the terms of the GNU Library General Public License as
  9. * published by the Free Software Foundation; either version 2 of
  10. * the License, or (at your option) any later version.
  11. *
  12. * This program is distributed in the hope that it will be useful,
  13. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  14. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  15. * GNU Library General Public License for more details.
  16. *
  17. * You should have received a copy of the GNU Library General Public
  18. * License along with this library; if not, write to the Free Software
  19. * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  20. *
  21. */
  22. #include <stdlib.h>
  23. #include <stdio.h>
  24. #include <string.h>
  25. #include <math.h>
  26. #ifndef M_PI
  27. #define M_PI 3.1415926535 // For OS's that don't include it
  28. #endif
  29. #include "filter.h"
  30. #include "filtercoeff.h"
  31. /* WARNING
  32. * The comments in this file are at best educated guesses.
  33. * I am not a DSP god and can not figure out what a complicated
  34. * math function does just by looking at it.
  35. */
  36. extern int getsample(float *inbuff, int nb);
  37. #define BLKAMP 1024
  38. // Block size
  39. #define BLKIN 1024
  40. #define Fc 2400.0
  41. #define DFc 50.0
  42. #define PixelLine 2080
  43. #define Fp (2 * PixelLine)
  44. #define RSMULT 15
  45. #define Fi (Fp * RSMULT)
  46. static double Fe;
  47. static double offset = 0.0;
  48. static double FreqLine = 1.0;
  49. static double FreqOsc;
  50. static double K1, K2;
  51. // Check if the input sample rate is correct
  52. int init_dsp(double F) {
  53. if(F > Fi) return(1);
  54. if(F < Fp) return(-1);
  55. Fe = F;
  56. K1 = DFc / Fe;
  57. K2 = K1 * K1 / 2.0;
  58. FreqOsc = Fc / Fe;
  59. return(0);
  60. }
  61. // Fast phase estimator
  62. // Calculates the phase angle of a signal from a IQ sample
  63. static inline double Phase(double I, double Q) {
  64. double angle, r;
  65. int s;
  66. if(I == 0.0 && Q == 0.0)
  67. return(0.0);
  68. if (Q < 0) {
  69. s = -1;
  70. Q = -Q;
  71. } else {
  72. s = 1;
  73. }
  74. if (I >= 0) {
  75. r = (I - Q) / (I + Q);
  76. angle = 0.25 - 0.25 * r;
  77. } else {
  78. r = (I + Q) / (Q - I);
  79. angle = 0.75 - 0.25 * r;
  80. }
  81. if(s > 0)
  82. return(angle);
  83. else
  84. return(-angle);
  85. }
  86. // Phase locked loop
  87. // Used to get value from an IQ sample with noise reduction
  88. static double pll(double I, double Q) {
  89. // PLL coefficient
  90. static double PhaseOsc = 0.0;
  91. double Io, Qo;
  92. double Ip, Qp;
  93. double DPhi;
  94. // Quadrature oscillator / reference
  95. Io = cos(PhaseOsc);
  96. Qo = sin(PhaseOsc);
  97. // Phase detector
  98. Ip = I * Io + Q * Qo;
  99. Qp = Q * Io - I * Qo;
  100. DPhi = Phase(Ip, Qp);
  101. // Loop filter
  102. PhaseOsc += 2.0 * M_PI * (K1 * DPhi + FreqOsc);
  103. if (PhaseOsc > M_PI)
  104. PhaseOsc -= 2.0 * M_PI;
  105. if (PhaseOsc <= -M_PI)
  106. PhaseOsc += 2.0 * M_PI;
  107. FreqOsc += K2 * DPhi;
  108. if (FreqOsc > ((Fc + DFc) / Fe))
  109. FreqOsc = (Fc + DFc) / Fe;
  110. if (FreqOsc < ((Fc - DFc) / Fe))
  111. FreqOsc = (Fc - DFc) / Fe;
  112. return(Ip);
  113. }
  114. // Convert audio samples into a pixel
  115. static int getamp(double *ambuff, int nb) {
  116. static float inbuff[BLKIN];
  117. static int idxin = 0;
  118. static int nin = 0;
  119. int n;
  120. for (n = 0; n < nb; n++) {
  121. double I, Q;
  122. // If the amount of samples is small enough to be processed
  123. if (nin < IQFilterLen * 2 + 2) {
  124. // Number of samples read
  125. int res;
  126. memmove(inbuff, &(inbuff[idxin]), nin * sizeof(float));
  127. idxin = 0;
  128. // Read some samples
  129. res = getsample(&(inbuff[nin]), BLKIN - nin);
  130. nin += res;
  131. // If we haven't read any more samples, return how far we got
  132. if (nin < IQFilterLen * 2 + 2)
  133. return(n);
  134. }
  135. // Process read samples into a brightness value
  136. iqfir(&inbuff[idxin], iqfilter, IQFilterLen, &I, &Q);
  137. ambuff[n] = pll(I, Q);
  138. idxin += 1;
  139. nin -= 1;
  140. }
  141. return(n);
  142. }
  143. // Get an entire row of pixels, without alignment
  144. int getpixelv(float *pvbuff, int nb) {
  145. // Amplitude buffer
  146. static double ambuff[BLKAMP];
  147. static int nam = 0;
  148. static int idxam = 0;
  149. int n, m;
  150. double mult;
  151. mult = (double) Fi / Fe * FreqLine;
  152. m = RSFilterLen / mult + 1;
  153. for (n = 0; n < nb; n++) {
  154. int shift;
  155. if (nam < m) {
  156. int res;
  157. memmove(ambuff, &(ambuff[idxam]), nam * sizeof(double));
  158. idxam = 0;
  159. res = getamp(&(ambuff[nam]), BLKAMP - nam);
  160. nam += res;
  161. if (nam < m)
  162. return(n);
  163. }
  164. // Denoise
  165. pvbuff[n] = rsfir(&(ambuff[idxam]), rsfilter, RSFilterLen, offset, mult) * mult * 256.0;
  166. shift = ((int) floor((RSMULT - offset) / mult)) + 1;
  167. offset = shift * mult + offset - RSMULT;
  168. idxam += shift;
  169. nam -= shift;
  170. }
  171. return(nb);
  172. }
  173. // Align this line based off of the synchronisation markers
  174. int getpixelrow(float *pixelv) {
  175. // Create an array for this row
  176. static float pixels[PixelLine + SyncFilterLen];
  177. static int npv = 0;
  178. static int synced = 0;
  179. static double max = 0.0;
  180. double corr, ecorr, lcorr;
  181. int res;
  182. if (npv > 0)
  183. memmove(pixelv, pixels, npv * sizeof(float));
  184. if (npv < SyncFilterLen + 2) {
  185. res = getpixelv(&(pixelv[npv]), SyncFilterLen + 2 - npv);
  186. npv += res;
  187. if (npv < SyncFilterLen + 2)
  188. return(0);
  189. }
  190. // Test current synchronisation
  191. ecorr = fir(pixelv, Sync, SyncFilterLen);
  192. corr = fir(&(pixelv[1]), Sync, SyncFilterLen - 1);
  193. lcorr = fir(&(pixelv[2]), Sync, SyncFilterLen - 2);
  194. // Calculate the per pixel offset
  195. FreqLine = 1.0+((ecorr-lcorr) / corr / PixelLine / 4.0);
  196. // Maximum acceptable offset
  197. if (corr < 0.75 * max) {
  198. synced = 0;
  199. FreqLine = 1.0;
  200. }
  201. max = corr;
  202. if (synced < 8) {
  203. int mshift;
  204. if (npv < PixelLine + SyncFilterLen) {
  205. res = getpixelv(&(pixelv[npv]), PixelLine + SyncFilterLen - npv);
  206. npv += res;
  207. if (npv < PixelLine + SyncFilterLen)
  208. return(0);
  209. }
  210. // Shift this line until we see the best results
  211. mshift = 0;
  212. for (int shift = 1; shift < PixelLine; shift++) {
  213. double corr;
  214. corr = fir(&(pixelv[shift + 1]), Sync, SyncFilterLen);
  215. if (corr > max) {
  216. mshift = shift;
  217. max = corr;
  218. }
  219. }
  220. // Shift memory, shifting this row
  221. if (mshift != 0) {
  222. memmove(pixelv, &(pixelv[mshift]), (npv - mshift) * sizeof(float));
  223. npv -= mshift;
  224. synced = 0;
  225. FreqLine = 1.0;
  226. } else
  227. synced += 1;
  228. }
  229. // If there are not enough pixels try to grab some more
  230. if (npv < PixelLine) {
  231. res = getpixelv(&(pixelv[npv]), PixelLine - npv);
  232. npv += res;
  233. // If we fail this then exit with 0 (which breaks the loop at main.c:338)
  234. if (npv < PixelLine)
  235. return(0);
  236. }
  237. // If we're finished reset npv to 0
  238. if (npv == PixelLine) {
  239. npv = 0;
  240. } else { // Move the pixel build buffer to the output buffer
  241. memmove(pixels, &(pixelv[PixelLine]), (npv - PixelLine) * sizeof(float));
  242. npv -= PixelLine;
  243. }
  244. return(1);
  245. }