Assists music production by grouping standalone programs into sessions. Community version of "Non Session Manager".
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.

266 lines
7.4KB

  1. /*******************************************************************************/
  2. /* Copyright (C) 2008 Jonathan Moore Liles */
  3. /* */
  4. /* This program is free software; you can redistribute it and/or modify it */
  5. /* under the terms of the GNU General Public License as published by the */
  6. /* Free Software Foundation; either version 2 of the License, or (at your */
  7. /* option) any later version. */
  8. /* */
  9. /* This program is distributed in the hope that it will be useful, but WITHOUT */
  10. /* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or */
  11. /* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for */
  12. /* more details. */
  13. /* */
  14. /* You should have received a copy of the GNU General Public License along */
  15. /* with This program; see the file COPYING. If not,write to the Free Software */
  16. /* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
  17. /*******************************************************************************/
  18. /**********/
  19. /* Engine */
  20. /**********/
  21. #include "../Audio_Region.H"
  22. #include "Audio_File.H"
  23. #include "dsp.h"
  24. #include "const.h"
  25. #include "const.h"
  26. #include "util/debug.h"
  27. #include "util/Thread.H"
  28. /** Apply a (portion of) fade from /start/ to /end/ assuming a
  29. * buffer size of /nframes/. /start/ and /end/ are relative to the
  30. * given buffer, and /start/ may be negative. */
  31. void
  32. Audio_Region::Fade::apply ( sample_t *buf, Audio_Region::Fade::fade_dir_e dir, long start, nframes_t end, nframes_t nframes ) const
  33. {
  34. // printf( "apply fade %s: start=%ld end=%lu\n", dir == Fade::Out ? "out" : "in", start, end );
  35. if ( ! nframes )
  36. return;
  37. const nframes_t i = start > 0 ? start : 0;
  38. const nframes_t e = end > nframes ? nframes : end;
  39. assert( i < nframes );
  40. const float inc = increment();
  41. float fi = ( i - start ) / (float)length;
  42. // buf += i;
  43. buf = &buf[ i ];
  44. nframes_t n = e - i;
  45. assert( i + n <= nframes );
  46. if ( dir == Fade::Out )
  47. {
  48. fi = 1.0f - fi;
  49. for ( ; n--; fi -= inc )
  50. *(buf++) *= gain( fi );
  51. }
  52. else
  53. for ( ; n--; fi += inc )
  54. *(buf++) *= gain( fi );
  55. }
  56. /** read the overlapping part of /channel/ at /pos/ for /nframes/ of
  57. this region into /buf/, where /pos/ is in timeline frames */
  58. /* this runs in the diskstream thread. */
  59. /* FIXME: it is far more efficient to read all the channels from a
  60. multichannel source at once... But how should we handle the case of a
  61. mismatch between the number of channels in this region's source and
  62. the number of channels on the track/buffer this data is being read
  63. for? Would it not be better to simply buffer and deinterlace the
  64. frames in the Audio_File class instead, so that sequential requests
  65. for different channels at the same position avoid hitting the disk
  66. again? */
  67. nframes_t
  68. Audio_Region::read ( sample_t *buf, nframes_t pos, nframes_t nframes, int channel ) const
  69. {
  70. THREAD_ASSERT( Playback );
  71. const Range r = _range;
  72. /* do nothing if we aren't covered by this frame range */
  73. if ( pos > r.start + r.length || pos + nframes < r.start )
  74. return 0;
  75. /* calculate offsets into file and sample buffer */
  76. nframes_t sofs, ofs, cnt;
  77. cnt = nframes;
  78. if ( pos < r.start )
  79. {
  80. sofs = 0;
  81. ofs = r.start - pos;
  82. cnt -= ofs;
  83. }
  84. else
  85. {
  86. ofs = 0;
  87. sofs = pos - r.start;
  88. }
  89. if ( ofs >= nframes )
  90. return 0;
  91. // const nframes_t start = ofs + r.start + sofs;
  92. const nframes_t start = r.offset + sofs;
  93. const nframes_t len = min( cnt, nframes - ofs );
  94. if ( len == 0 )
  95. return 0;
  96. /* now that we know how much and where to read, get on with it */
  97. // printf( "reading region ofs = %lu, sofs = %lu, %lu-%lu\n", ofs, sofs, start, end );
  98. if ( _loop )
  99. {
  100. nframes_t lofs = sofs % _loop;
  101. nframes_t lstart = r.offset + lofs;
  102. if ( lofs + len > _loop )
  103. {
  104. /* this buffer covers a loop bounary */
  105. /* read the first part */
  106. cnt = _clip->read( buf + ofs, channel, lstart, len - ( ( lofs + len ) - _loop ) );
  107. /* read the second part */
  108. cnt += _clip->read( buf + ofs + cnt, channel, lstart + cnt, len - cnt );
  109. /* TODO: declick/crossfade transition? */
  110. assert( cnt == len );
  111. }
  112. else
  113. cnt = _clip->read( buf + ofs, channel, lstart, len );
  114. }
  115. else
  116. cnt = _clip->read( buf + ofs, channel, start, len );
  117. /* apply gain */
  118. buffer_apply_gain( buf + ofs, cnt, _scale );
  119. /* perform declicking if necessary */
  120. /* FIXME: keep the declick defults someplace else */
  121. Fade declick;
  122. declick.length = 256;
  123. declick.type = Fade::Linear;
  124. {
  125. Fade fade;
  126. fade = declick < _fade_in ? _fade_in : declick;
  127. /* do fade in if necessary */
  128. if ( sofs < fade.length )
  129. {
  130. const long d = 0L - (long)sofs;
  131. assert( cnt <= nframes );
  132. fade.apply( buf + ofs, Fade::In, d, d + fade.length, cnt );
  133. }
  134. fade = declick < _fade_out ? _fade_out : declick;
  135. /* do fade out if necessary */
  136. // if ( start + cnt + fade.length > r.end )
  137. if ( start + fade.length > ( r.offset + r.length ) )
  138. {
  139. const nframes_t d = ( r.offset + r.length ) - start;
  140. assert( cnt <= nframes );
  141. fade.apply( buf, Fade::Out, cnt + (long)d - fade.length, cnt + d, cnt );
  142. }
  143. }
  144. // printf( "read %lu frames\n", cnt );
  145. return cnt;
  146. }
  147. /** prepare for capturing */
  148. void
  149. Audio_Region::prepare ( void )
  150. {
  151. log_start();
  152. }
  153. /** write /nframes/ from /buf/ to source. /buf/ is interleaved and
  154. must match the channel layout of the write source! */
  155. nframes_t
  156. Audio_Region::write ( nframes_t nframes )
  157. {
  158. THREAD_ASSERT( Capture );
  159. _range.length += nframes;
  160. /* FIXME: too much? */
  161. // _track->damage( FL_DAMAGE_EXPOSE, x() + w(), y(), 10/* FIXME: guess */, h() );
  162. if ( 0 == ( timeline->ts_to_x( _range.length ) % 20 ) )
  163. {
  164. nframes_t oldl = _clip->length();
  165. /* get the new size. Remember, this is a read-only handle on the source--not the same
  166. one being written to */
  167. _clip->close();
  168. _clip->open();
  169. int W = timeline->ts_to_x( _clip->length() - oldl );
  170. /* why - 1? */
  171. if ( W )
  172. {
  173. ++W;
  174. Fl::lock();
  175. sequence()->damage( FL_DAMAGE_ALL, x() + w() - W, y(), W, h() );
  176. // Fl::awake();
  177. Fl::unlock();
  178. }
  179. }
  180. return nframes;
  181. }
  182. /** finalize region capture. Assumes that this *is* a captured region
  183. and that no other regions refer to the same source */
  184. bool
  185. Audio_Region::finalize ( nframes_t frame )
  186. {
  187. THREAD_ASSERT( Capture );
  188. DMESSAGE( "finalizing capture region" );
  189. _range.length = frame - _range.start;
  190. log_end();
  191. _clip->close();
  192. _clip->open();
  193. /* FIXME: should we attempt to truncate the file? */
  194. Fl::lock();
  195. redraw();
  196. Fl::awake();
  197. Fl::unlock();
  198. return true;
  199. }