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

preview.js 3.6KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182
  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, heightFactor;
  50. if (height > width) {
  51. widthFactor = 360 / width;
  52. heightFactor = 640 / height;
  53. } else {
  54. widthFactor = 640 / width;
  55. heightFactor = 360 / height;
  56. }
  57. var factor = Math.min(widthFactor, heightFactor);
  58. d3.select("canvas")
  59. .attr("width", factor * width)
  60. .attr("height", factor * height);
  61. d3.select("#canvas")
  62. .style("width", (factor * width) + "px");
  63. d3.select("video")
  64. .attr("height", widthFactor * height);
  65. d3.select("#video")
  66. .attr("height", (widthFactor * height) + "px");
  67. context.setTransform(factor, 0, 0, factor, 0, 0);
  68. }
  69. function redraw() {
  70. resize(theme.width, theme.height);
  71. video.kill();
  72. var renderer = getRenderer(theme);
  73. renderer.backgroundImage(theme.backgroundImageFile || null);
  74. renderer.drawFrame(context, {
  75. caption: caption,
  76. waveform: sampleWave,
  77. frame: 0
  78. });
  79. if (location.pathname === "/theme") {
  80. const noPattern = (theme.noPattern === undefined) ? false : theme.noPattern;
  81. d3.select("#chkNoPattern").property("checked", noPattern);
  82. const font = theme.subtitleFont;
  83. if (font !== undefined) {
  84. var fontName = font.substring(font.indexOf("'"));
  85. fontName = fontName.substring(1, fontName.length-1);
  86. d3.select("#input-font").property("value", fontName);
  87. }
  88. }
  89. }
  90. function loadAudio(f, cb) {
  91. d3.queue()
  92. .defer(getWaveform, f)
  93. .defer(audio.src, f)
  94. .await(function(err, data){
  95. if (err) {
  96. return cb(err);
  97. }
  98. file = f;
  99. minimap.redraw(data.peaks);
  100. cb(err);
  101. });
  102. }
  103. function loadNewTheme(f, cb) {
  104. d3.queue()
  105. .await(function(err, data){
  106. if (err) {
  107. return cb(err);
  108. }
  109. newTheme = f;
  110. cb(err);
  111. });
  112. }
  113. function loadSubtitle(f, cb) {
  114. d3.queue()
  115. .await(function(err, data){
  116. if (err) {
  117. return cb(err);
  118. }
  119. subtitle = f;
  120. cb(err);
  121. });
  122. }
  123. module.exports = {
  124. caption: _caption,
  125. theme: _theme,
  126. file: _file,
  127. selection: _selection,
  128. loadAudio: loadAudio,
  129. newTheme: _newTheme,
  130. newCaption: _newCaption,
  131. loadNewTheme: loadNewTheme,
  132. subtitle: _subtitle,
  133. loadSubtitle: loadSubtitle
  134. };