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.

403 lines
9.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. #include "Peaks.H"
  19. // #include "Timeline.H"
  20. #include <sys/mman.h>
  21. #include <sys/types.h>
  22. #include <sys/stat.h>
  23. #include <unistd.h>
  24. #include <fcntl.h>
  25. #include <stdlib.h>
  26. #include <stdio.h>
  27. #include <string.h>
  28. #include <sndfile.h>
  29. #include "Audio_File.H"
  30. #include "assert.h"
  31. #include <math.h>
  32. #include <FL/Fl.H> // for Fl::check();
  33. Peaks::peakbuffer Peaks::_peakbuf;
  34. static
  35. const char *
  36. peakname ( const char *filename, int chunksize )
  37. {
  38. static char file[512];
  39. snprintf( file, 512, "%s-[%d].peak", filename, chunksize );
  40. return (const char*)&file;
  41. }
  42. /** Prepare a buffer of peaks from /s/ to /e/ for reading. Must be
  43. * called before any calls to operator[] */
  44. int
  45. Peaks::fill_buffer ( float fpp, nframes_t s, nframes_t e ) const
  46. {
  47. _fpp = fpp;
  48. return read_peaks( s, e, (e - s) / fpp, fpp );
  49. }
  50. static int
  51. nearest_power_of_two ( int v )
  52. {
  53. int p = 1;
  54. while ( 1 << p < v )
  55. ++p;
  56. return 1 << p;
  57. }
  58. const int MAX_CHUNKSIZE = 4096;
  59. const int MIN_CHUNKSIZE = 256;
  60. int
  61. Peaks::read_peakfile_peaks ( Peak *peaks, nframes_t s, int npeaks, int chunksize ) const
  62. {
  63. FILE *fp;
  64. int best_fit = nearest_power_of_two( chunksize );
  65. int pfchunksize;
  66. // for ( pfchunksize = best_fit; pfchunksize < MAX_CHUNKSIZE; pfchunksize <<= 1 )
  67. for ( pfchunksize = best_fit; pfchunksize >= MIN_CHUNKSIZE; pfchunksize >>= 1 )
  68. if ( ( fp = fopen( peakname( _clip->name(), pfchunksize ), "r" ) ) )
  69. break;
  70. if ( ! fp )
  71. {
  72. printf( "failed to open peak file!\n" );
  73. return 0;
  74. }
  75. int channels = _clip->channels();
  76. const int ratio = chunksize / pfchunksize;
  77. /* locate to start position */
  78. if ( fseek( fp, (s * channels / pfchunksize) * sizeof( Peak ), SEEK_CUR ) )
  79. /* failed to seek... peaks not ready? */
  80. return 0;
  81. if ( ratio == 1 )
  82. {
  83. int len = fread( peaks, sizeof( Peak ) * channels, npeaks, fp );
  84. fclose( fp );
  85. return len;
  86. }
  87. Peak *pbuf = new Peak[ ratio * channels ];
  88. size_t len = 0;
  89. int i;
  90. for ( i = 0; i < npeaks; ++i )
  91. {
  92. /* read in a buffer */
  93. len = fread( pbuf, sizeof( Peak ) * channels, ratio, fp );
  94. Peak *pk = peaks + (i * channels);
  95. /* get the peak for each channel */
  96. for ( int j = 0; j < channels; ++j )
  97. {
  98. Peak *p = &pk[ j ];
  99. p->min = 0;
  100. p->max = 0;
  101. const Peak *pb = pbuf + j;
  102. for ( int k = len * channels; k--; pb += channels )
  103. {
  104. if ( pb->max > p->max )
  105. p->max = pb->max;
  106. if ( pb->min < p->min )
  107. p->min = pb->min;
  108. }
  109. }
  110. if ( len < ratio )
  111. break;
  112. }
  113. delete[] pbuf;
  114. fclose( fp );
  115. return i;
  116. }
  117. int
  118. Peaks::read_source_peaks ( Peak *peaks, int npeaks, int chunksize ) const
  119. {
  120. int channels = _clip->channels();
  121. sample_t *fbuf = new sample_t[ chunksize * channels ];
  122. size_t len;
  123. int i;
  124. for ( i = 0; i < npeaks; ++i )
  125. {
  126. /* read in a buffer */
  127. len = _clip->read( fbuf, -1, chunksize );
  128. Peak *pk = peaks + (i * channels);
  129. /* get the peak for each channel */
  130. for ( int j = 0; j < channels; ++j )
  131. {
  132. Peak &p = pk[ j ];
  133. p.min = 0;
  134. p.max = 0;
  135. for ( int k = j; k < len * channels; k += channels )
  136. {
  137. if ( fbuf[ k ] > p.max )
  138. p.max = fbuf[ k ];
  139. if ( fbuf[ k ] < p.min )
  140. p.min = fbuf[ k ];
  141. }
  142. }
  143. if ( len < chunksize )
  144. break;
  145. }
  146. delete[] fbuf;
  147. return i;
  148. }
  149. int
  150. Peaks::read_source_peaks ( Peak *peaks, nframes_t s, int npeaks, int chunksize ) const
  151. {
  152. // _clip->open();
  153. _clip->seek( s );
  154. int i = read_source_peaks( peaks, npeaks, chunksize );
  155. // _clip->close();
  156. return i;
  157. }
  158. int
  159. Peaks::read_peaks ( nframes_t s, nframes_t e, int npeaks, int chunksize ) const
  160. {
  161. printf( "reading peaks %d @ %d\n", npeaks, chunksize );
  162. if ( _peakbuf.size < npeaks * _clip->channels() )
  163. {
  164. _peakbuf.size = npeaks * _clip->channels();
  165. // printf( "reallocating peak buffer %li\n", _peakbuf.size );
  166. _peakbuf.buf = (peakdata*)realloc( _peakbuf.buf, sizeof( peakdata ) + (_peakbuf.size * sizeof( Peak )) );
  167. }
  168. assert( s >= 0 );
  169. _peakbuf.offset = s;
  170. _peakbuf.buf->chunksize = chunksize;
  171. /* FIXME: compart to (minimum) peakfile chunk size */
  172. if ( chunksize < 256 )
  173. _peakbuf.len = read_source_peaks( _peakbuf.buf->data, s, npeaks, chunksize );
  174. else
  175. _peakbuf.len = read_peakfile_peaks( _peakbuf.buf->data, s, npeaks, chunksize );
  176. return _peakbuf.len;
  177. }
  178. bool
  179. Peaks::open ( void )
  180. {
  181. const char *filename = _clip->name();
  182. int fd;
  183. if ( ! current() )
  184. /* Build peaks asyncronously */
  185. if ( ! fork() )
  186. exit( make_peaks( 256 ) );
  187. /* FIXME: 256 == bogus */
  188. if ( ( fd = ::open( peakname( filename, 256 ), O_RDONLY ) ) < 0 )
  189. return false;
  190. {
  191. struct stat st;
  192. fstat( fd, &st );
  193. _len = st.st_size;
  194. }
  195. ::close( fd );
  196. _len = (_len - sizeof( int )) / sizeof( Peak );
  197. return true;
  198. }
  199. /** returns false if peak file for /filename/ is out of date */
  200. bool
  201. Peaks::current ( void ) const
  202. {
  203. int sfd, pfd;
  204. if ( ( sfd = ::open( _clip->name(), O_RDONLY ) ) < 0 )
  205. return true;
  206. /* FIXME: 256 == bogus */
  207. if ( ( pfd = ::open( peakname( _clip->name(), 256 ), O_RDONLY ) ) < 0 )
  208. return false;
  209. struct stat sst, pst;
  210. fstat( sfd, &sst );
  211. fstat( pfd, &pst );
  212. close( sfd );
  213. close( pfd );
  214. return sst.st_mtime <= pst.st_mtime;
  215. }
  216. /* FIXME: we need to work out a way to run this in another thread and
  217. possibly stream back the data to the GUI */
  218. /** build peaks file for /filename/ if necessary */
  219. bool
  220. Peaks::make_peaks ( int chunksize )
  221. {
  222. const char *filename = _clip->name();
  223. if ( current() )
  224. return true;
  225. _clip->seek( 0 );
  226. FILE *fp = fopen( peakname( filename, chunksize ), "w" );
  227. if ( ! fp )
  228. return false;
  229. Peak peaks[ _clip->channels() ];
  230. size_t len;
  231. do {
  232. len = read_source_peaks( peaks, 1, chunksize );
  233. fwrite( peaks, sizeof( peaks ), 1, fp );
  234. }
  235. while ( len );
  236. fclose( fp );
  237. return true;
  238. }
  239. /** return normalization factor for range of samples from /start/ to
  240. /end/ (uses known peak data if possible */
  241. /* float */
  242. /* Peaks::normalization_factor( float fpp, nframes_t start, nframes_t end ) const */
  243. /* { */
  244. /* float s; */
  245. /* // fill_buffer( fpp, start, end ); */
  246. /* /\* if ( end - start < _peaks->chunksize * 4 ) *\/ */
  247. /* /\* fill_buffer( _clip->length() / 4, start, end ); *\/ */
  248. /* /\* else *\/ */
  249. /* /\* fill_buffer( _clip->length(), start, end ); *\/ */
  250. /* Peak p = peak( start, end ); */
  251. /* s = 1.0f / fabs( p.max ); */
  252. /* if ( s * p.min < -1.0 ) */
  253. /* s = 1.0f / fabs( p.min ); */
  254. /* return s; */
  255. /* } */
  256. Peak_Writer::Peak_Writer ( const char *filename, int chunksize, int channels )
  257. {
  258. _channels = channels;
  259. _chunksize = chunksize;
  260. _index = 0;
  261. _peak = new Peak[ channels ];
  262. memset( _peak, 0, sizeof( Peak ) * channels );
  263. if ( ! ( _fp = fopen( peakname( filename, chunksize ), "w" ) ) )
  264. /* error! */;
  265. }
  266. Peak_Writer::~Peak_Writer ( )
  267. {
  268. fclose( _fp );
  269. delete _peak;
  270. }
  271. /** append peaks for samples in /buf/ to peakfile */
  272. void
  273. Peak_Writer::write ( sample_t *buf, nframes_t nframes )
  274. {
  275. for ( ; nframes--; ++_index, buf += _channels )
  276. {
  277. for ( int j = 0; j < _channels; ++j )
  278. {
  279. Peak *p = _peak + j;
  280. if ( *buf > p->max )
  281. p->max = *buf;
  282. if ( *buf < p->min )
  283. p->min = *buf;
  284. }
  285. if ( _index == _chunksize - 1 )
  286. {
  287. fwrite( _peak, sizeof( Peak ), _channels, _fp );
  288. memset( _peak, 0, sizeof( Peak ) * _channels );
  289. _index = 0;
  290. }
  291. }
  292. }