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.

246 lines
8.6KB

  1. /*
  2. * Copyright (c) 2015 Kyle Swanson <k@ylo.ph>.
  3. *
  4. * This file is part of FFmpeg.
  5. *
  6. * FFmpeg is free software; you can redistribute it and/or
  7. * modify it under the terms of the GNU Lesser General Public License
  8. * as published by the Free Software Foundation; either
  9. * version 2.1 of the License, or (at your option) any later version.
  10. *
  11. * FFmpeg is distributed in the hope that it will be useful,
  12. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  14. * GNU Lesser General Public License for more details.
  15. *
  16. * You should have received a copy of the GNU Lesser General Public License
  17. * along with FFmpeg; if not, write to the Free Software Foundation, Inc.,
  18. * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
  19. */
  20. #include "libavutil/opt.h"
  21. #include "audio.h"
  22. #include "avfilter.h"
  23. #include "internal.h"
  24. #include "libavutil/lfg.h"
  25. #include "libavutil/random_seed.h"
  26. typedef struct ANoiseSrcContext {
  27. const AVClass *class;
  28. int sample_rate;
  29. double amplitude;
  30. int64_t duration;
  31. int64_t color;
  32. int64_t seed;
  33. int nb_samples;
  34. int64_t pts;
  35. int infinite;
  36. double (*filter)(double white, double *buf);
  37. double buf[7];
  38. AVLFG c;
  39. } ANoiseSrcContext;
  40. enum NoiseMode {
  41. NM_WHITE,
  42. NM_PINK,
  43. NM_BROWN,
  44. NM_BLUE,
  45. NM_VIOLET,
  46. NM_NB
  47. };
  48. #define OFFSET(x) offsetof(ANoiseSrcContext, x)
  49. #define FLAGS AV_OPT_FLAG_AUDIO_PARAM|AV_OPT_FLAG_FILTERING_PARAM
  50. static const AVOption anoisesrc_options[] = {
  51. { "sample_rate", "set sample rate", OFFSET(sample_rate), AV_OPT_TYPE_INT, {.i64 = 48000}, 15, INT_MAX, FLAGS },
  52. { "r", "set sample rate", OFFSET(sample_rate), AV_OPT_TYPE_INT, {.i64 = 48000}, 15, INT_MAX, FLAGS },
  53. { "amplitude", "set amplitude", OFFSET(amplitude), AV_OPT_TYPE_DOUBLE, {.dbl = 1.}, 0., 1., FLAGS },
  54. { "a", "set amplitude", OFFSET(amplitude), AV_OPT_TYPE_DOUBLE, {.dbl = 1.}, 0., 1., FLAGS },
  55. { "duration", "set duration", OFFSET(duration), AV_OPT_TYPE_DURATION, {.i64 = 0}, 0, INT64_MAX, FLAGS },
  56. { "d", "set duration", OFFSET(duration), AV_OPT_TYPE_DURATION, {.i64 = 0}, 0, INT64_MAX, FLAGS },
  57. { "color", "set noise color", OFFSET(color), AV_OPT_TYPE_INT, {.i64 = 0}, 0, NM_NB - 1, FLAGS, "color" },
  58. { "colour", "set noise color", OFFSET(color), AV_OPT_TYPE_INT, {.i64 = 0}, 0, NM_NB - 1, FLAGS, "color" },
  59. { "c", "set noise color", OFFSET(color), AV_OPT_TYPE_INT, {.i64 = 0}, 0, NM_NB - 1, FLAGS, "color" },
  60. { "white", 0, 0, AV_OPT_TYPE_CONST, {.i64 = NM_WHITE}, 0, 0, FLAGS, "color" },
  61. { "pink", 0, 0, AV_OPT_TYPE_CONST, {.i64 = NM_PINK}, 0, 0, FLAGS, "color" },
  62. { "brown", 0, 0, AV_OPT_TYPE_CONST, {.i64 = NM_BROWN}, 0, 0, FLAGS, "color" },
  63. { "blue", 0, 0, AV_OPT_TYPE_CONST, {.i64 = NM_BLUE}, 0, 0, FLAGS, "color" },
  64. { "violet", 0, 0, AV_OPT_TYPE_CONST, {.i64 = NM_VIOLET}, 0, 0, FLAGS, "color" },
  65. { "seed", "set random seed", OFFSET(seed), AV_OPT_TYPE_INT64, {.i64 = -1}, -1, UINT_MAX, FLAGS },
  66. { "s", "set random seed", OFFSET(seed), AV_OPT_TYPE_INT64, {.i64 = -1}, -1, UINT_MAX, FLAGS },
  67. { "nb_samples", "set the number of samples per requested frame", OFFSET(nb_samples), AV_OPT_TYPE_INT, {.i64 = 1024}, 1, INT_MAX, FLAGS },
  68. { "n", "set the number of samples per requested frame", OFFSET(nb_samples), AV_OPT_TYPE_INT, {.i64 = 1024}, 1, INT_MAX, FLAGS },
  69. {NULL}
  70. };
  71. AVFILTER_DEFINE_CLASS(anoisesrc);
  72. static av_cold int query_formats(AVFilterContext *ctx)
  73. {
  74. ANoiseSrcContext *s = ctx->priv;
  75. static const int64_t chlayouts[] = { AV_CH_LAYOUT_MONO, -1 };
  76. int sample_rates[] = { s->sample_rate, -1 };
  77. static const enum AVSampleFormat sample_fmts[] = {
  78. AV_SAMPLE_FMT_DBL,
  79. AV_SAMPLE_FMT_NONE
  80. };
  81. AVFilterFormats *formats;
  82. AVFilterChannelLayouts *layouts;
  83. int ret;
  84. formats = ff_make_format_list(sample_fmts);
  85. if (!formats)
  86. return AVERROR(ENOMEM);
  87. ret = ff_set_common_formats (ctx, formats);
  88. if (ret < 0)
  89. return ret;
  90. layouts = avfilter_make_format64_list(chlayouts);
  91. if (!layouts)
  92. return AVERROR(ENOMEM);
  93. ret = ff_set_common_channel_layouts(ctx, layouts);
  94. if (ret < 0)
  95. return ret;
  96. formats = ff_make_format_list(sample_rates);
  97. if (!formats)
  98. return AVERROR(ENOMEM);
  99. return ff_set_common_samplerates(ctx, formats);
  100. }
  101. static double white_filter(double white, double *buf)
  102. {
  103. return white;
  104. }
  105. static double pink_filter(double white, double *buf)
  106. {
  107. double pink;
  108. /* http://www.musicdsp.org/files/pink.txt */
  109. buf[0] = 0.99886 * buf[0] + white * 0.0555179;
  110. buf[1] = 0.99332 * buf[1] + white * 0.0750759;
  111. buf[2] = 0.96900 * buf[2] + white * 0.1538520;
  112. buf[3] = 0.86650 * buf[3] + white * 0.3104856;
  113. buf[4] = 0.55000 * buf[4] + white * 0.5329522;
  114. buf[5] = -0.7616 * buf[5] - white * 0.0168980;
  115. pink = buf[0] + buf[1] + buf[2] + buf[3] + buf[4] + buf[5] + buf[6] + white * 0.5362;
  116. buf[6] = white * 0.115926;
  117. return pink * 0.11;
  118. }
  119. static double blue_filter(double white, double *buf)
  120. {
  121. double blue;
  122. /* Same as pink_filter but subtract the offsets rather than add */
  123. buf[0] = 0.0555179 * white - 0.99886 * buf[0];
  124. buf[1] = 0.0750759 * white - 0.99332 * buf[1];
  125. buf[2] = 0.1538520 * white - 0.96900 * buf[2];
  126. buf[3] = 0.3104856 * white - 0.86650 * buf[3];
  127. buf[4] = 0.5329522 * white - 0.55000 * buf[4];
  128. buf[5] = -0.016898 * white + 0.76160 * buf[5];
  129. blue = buf[0] + buf[1] + buf[2] + buf[3] + buf[4] + buf[5] + buf[6] + white * 0.5362;
  130. buf[6] = white * 0.115926;
  131. return blue * 0.11;
  132. }
  133. static double brown_filter(double white, double *buf)
  134. {
  135. double brown;
  136. brown = ((0.02 * white) + buf[0]) / 1.02;
  137. buf[0] = brown;
  138. return brown * 3.5;
  139. }
  140. static double violet_filter(double white, double *buf)
  141. {
  142. double violet;
  143. violet = ((0.02 * white) - buf[0]) / 1.02;
  144. buf[0] = violet;
  145. return violet * 3.5;
  146. }
  147. static av_cold int config_props(AVFilterLink *outlink)
  148. {
  149. AVFilterContext *ctx = outlink->src;
  150. ANoiseSrcContext *s = ctx->priv;
  151. if (s->seed == -1)
  152. s->seed = av_get_random_seed();
  153. av_lfg_init(&s->c, s->seed);
  154. if (s->duration == 0)
  155. s->infinite = 1;
  156. s->duration = av_rescale(s->duration, s->sample_rate, AV_TIME_BASE);
  157. switch (s->color) {
  158. case NM_WHITE: s->filter = white_filter; break;
  159. case NM_PINK: s->filter = pink_filter; break;
  160. case NM_BROWN: s->filter = brown_filter; break;
  161. case NM_BLUE: s->filter = blue_filter; break;
  162. case NM_VIOLET: s->filter = violet_filter; break;
  163. }
  164. return 0;
  165. }
  166. static int request_frame(AVFilterLink *outlink)
  167. {
  168. AVFilterContext *ctx = outlink->src;
  169. ANoiseSrcContext *s = ctx->priv;
  170. AVFrame *frame;
  171. int nb_samples, i;
  172. double *dst;
  173. if (!s->infinite && s->duration <= 0) {
  174. return AVERROR_EOF;
  175. } else if (!s->infinite && s->duration < s->nb_samples) {
  176. nb_samples = s->duration;
  177. } else {
  178. nb_samples = s->nb_samples;
  179. }
  180. if (!(frame = ff_get_audio_buffer(outlink, nb_samples)))
  181. return AVERROR(ENOMEM);
  182. dst = (double *)frame->data[0];
  183. for (i = 0; i < nb_samples; i++) {
  184. double white;
  185. white = s->amplitude * ((2 * ((double) av_lfg_get(&s->c) / 0xffffffff)) - 1);
  186. dst[i] = s->filter(white, s->buf);
  187. }
  188. if (!s->infinite)
  189. s->duration -= nb_samples;
  190. frame->pts = s->pts;
  191. s->pts += nb_samples;
  192. return ff_filter_frame(outlink, frame);
  193. }
  194. static const AVFilterPad anoisesrc_outputs[] = {
  195. {
  196. .name = "default",
  197. .type = AVMEDIA_TYPE_AUDIO,
  198. .request_frame = request_frame,
  199. .config_props = config_props,
  200. },
  201. { NULL }
  202. };
  203. AVFilter ff_asrc_anoisesrc = {
  204. .name = "anoisesrc",
  205. .description = NULL_IF_CONFIG_SMALL("Generate a noise audio signal."),
  206. .query_formats = query_formats,
  207. .priv_size = sizeof(ANoiseSrcContext),
  208. .inputs = NULL,
  209. .outputs = anoisesrc_outputs,
  210. .priv_class = &anoisesrc_class,
  211. };