Turn audio into a shareable video. forked from nypublicradio/audiogram

preview.js 3.1KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166
  1. var d3 = require("d3"),
  2. audio = require("./audio.js"),
  3. video = require("./video.js"),
  4. minimap = require("./minimap.js"),
  5. sampleWave = require("./sample-wave.js"),
  6. getRenderer = require("../renderer/"),
  7. getWaveform = require("./waveform.js");
  8. var context = d3.select("canvas").node().getContext("2d");
  9. var theme,
  10. caption,
  11. file,
  12. selection,
  13. newTheme,
  14. newCaption,
  15. subtitle;
  16. function _file(_) {
  17. return arguments.length ? (file = _) : file;
  18. }
  19. function _theme(_) {
  20. return arguments.length ? (theme = _, redraw()) : theme;
  21. }
  22. function _caption(_) {
  23. return arguments.length ? (caption = _, redraw()) : caption;
  24. }
  25. function _selection(_) {
  26. return arguments.length ? (selection = _) : selection;
  27. }
  28. function _newTheme(_) {
  29. return arguments.length ? (newTheme = _) : newTheme;
  30. }
  31. function _newCaption(_) {
  32. return arguments.length ? (newCaption = _) : newCaption;
  33. }
  34. function _subtitle(_) {
  35. return arguments.length ? (subtitle = _) : subtitle;
  36. }
  37. minimap.onBrush(function(extent){
  38. var duration = audio.duration();
  39. selection = {
  40. duration: duration * (extent[1] - extent[0]),
  41. start: extent[0] ? extent[0] * duration : null,
  42. end: extent[1] < 1 ? extent[1] * duration : null
  43. };
  44. d3.select("#duration strong").text(Math.round(10 * selection.duration) / 10)
  45. .classed("red", theme && theme.maxDuration && theme.maxDuration < selection.duration);
  46. });
  47. // Resize video and preview canvas to maintain aspect ratio
  48. function resize(width, height) {
  49. var widthFactor = 640 / width,
  50. heightFactor = 360 / height,
  51. factor = Math.min(widthFactor, heightFactor);
  52. d3.select("canvas")
  53. .attr("width", factor * width)
  54. .attr("height", factor * height);
  55. d3.select("#canvas")
  56. .style("width", (factor * width) + "px");
  57. d3.select("video")
  58. .attr("height", widthFactor * height);
  59. d3.select("#video")
  60. .attr("height", (widthFactor * height) + "px");
  61. context.setTransform(factor, 0, 0, factor, 0, 0);
  62. }
  63. function redraw() {
  64. resize(theme.width, theme.height);
  65. video.kill();
  66. var renderer = getRenderer(theme);
  67. renderer.backgroundImage(theme.backgroundImageFile || null);
  68. renderer.drawFrame(context, {
  69. caption: caption,
  70. waveform: sampleWave,
  71. frame: 0
  72. });
  73. }
  74. function loadAudio(f, cb) {
  75. d3.queue()
  76. .defer(getWaveform, f)
  77. .defer(audio.src, f)
  78. .await(function(err, data){
  79. if (err) {
  80. return cb(err);
  81. }
  82. file = f;
  83. minimap.redraw(data.peaks);
  84. cb(err);
  85. });
  86. }
  87. function loadNewTheme(f, cb) {
  88. d3.queue()
  89. .await(function(err, data){
  90. if (err) {
  91. return cb(err);
  92. }
  93. newTheme = f;
  94. cb(err);
  95. });
  96. }
  97. function loadSubtitle(f, cb) {
  98. d3.queue()
  99. .await(function(err, data){
  100. if (err) {
  101. return cb(err);
  102. }
  103. subtitle = f;
  104. cb(err);
  105. });
  106. }
  107. module.exports = {
  108. caption: _caption,
  109. theme: _theme,
  110. file: _file,
  111. selection: _selection,
  112. loadAudio: loadAudio,
  113. newTheme: _newTheme,
  114. newCaption: _newCaption,
  115. loadNewTheme: loadNewTheme,
  116. subtitle: _subtitle,
  117. loadSubtitle: loadSubtitle
  118. };