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.

498 lines
11KB

  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 )
  37. {
  38. static char file[512];
  39. snprintf( file, 512, "%s.peak", filename );
  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. /* inline void */
  51. /* Peaks::downsample ( Peak *peaks, int s, int e, float *mhi, float *mlo ) const */
  52. /* { */
  53. /* *mhi = 0; */
  54. /* *mlo = 0; */
  55. /* if ( e > _len ) */
  56. /* e = _len; */
  57. /* for ( int j = s; j < e; j++ ) */
  58. /* { */
  59. /* const float lo = peaks[ j ].min; */
  60. /* const float hi = peaks[ j ].max; */
  61. /* if ( hi > *mhi ) */
  62. /* *mhi = hi; */
  63. /* if ( lo < *mlo ) */
  64. /* *mlo = lo; */
  65. /* } */
  66. /* } */
  67. #if 0
  68. const int HEADER_SIZE = 24;
  69. bool
  70. Peaks::read_header ( void )
  71. {
  72. int major, minor;
  73. if ( 2 != fscanf( _fp, "NON-PEAKS%2d%2d", &major, &minor ) )
  74. return false;
  75. if ( major != VERSION_MAJOR )
  76. /* incompatible version */
  77. return false;
  78. int data[3];
  79. int header_size;
  80. fread( &header_size, sizeof( int ), 1, _fp );
  81. if ( header_size < sizeof( data ) )
  82. return false;
  83. fread( data, sizeof( data ), 1, _fp );
  84. int chunksize = data[1];
  85. int channels = data[2];
  86. int peaksize = data[3];
  87. _data_offset = header_size + 12;
  88. if ( header_size > sizeof( data ) )
  89. fseek( _fp, _data_offset, SEEK_SET );
  90. return true;
  91. }
  92. #endif
  93. int
  94. Peaks::read_peakfile_peaks ( Peak *peaks, nframes_t s, int npeaks, int chunksize ) const
  95. {
  96. FILE *fp;
  97. if ( ! ( fp = fopen( peakname( _clip->name() ), "r" ) ) )
  98. {
  99. printf( "failed to open peak file!\n" );
  100. return 0;
  101. }
  102. /* get chunk size of peak file */
  103. /* FIXME: bogus */
  104. int pfchunksize = 256;
  105. /* if ( fread( &pfchunksize, sizeof( int ), 1, fp ) != 1 ) */
  106. /* { */
  107. /* printf( "invalid peak file!\n" ); */
  108. /* return 0; */
  109. /* } */
  110. int channels = _clip->channels();
  111. const int ratio = chunksize / pfchunksize;
  112. /* locate to start position */
  113. if ( fseek( fp, (s * channels / pfchunksize) * sizeof( Peak ), SEEK_CUR ) )
  114. /* failed to seek... peaks not ready? */
  115. return 0;
  116. if ( ratio == 1 )
  117. {
  118. int len = fread( peaks, sizeof( Peak ) * channels, npeaks, fp );
  119. fclose( fp );
  120. return len;
  121. }
  122. Peak *pbuf = new Peak[ ratio * channels ];
  123. size_t len = 0;
  124. int i;
  125. for ( i = 0; i < npeaks; ++i )
  126. {
  127. /* read in a buffer */
  128. len = fread( pbuf, sizeof( Peak ) * channels, ratio, fp );
  129. Peak *pk = peaks + (i * channels);
  130. /* get the peak for each channel */
  131. for ( int j = 0; j < channels; ++j )
  132. {
  133. Peak *p = &pk[ j ];
  134. p->min = 0;
  135. p->max = 0;
  136. const Peak *pb = pbuf + j;
  137. for ( int k = len * channels; k--; pb += channels )
  138. {
  139. if ( pb->max > p->max )
  140. p->max = pb->max;
  141. if ( pb->min < p->min )
  142. p->min = pb->min;
  143. }
  144. }
  145. if ( len < ratio )
  146. break;
  147. }
  148. delete[] pbuf;
  149. fclose( fp );
  150. return i;
  151. }
  152. int
  153. Peaks::read_source_peaks ( Peak *peaks, int npeaks, int chunksize ) const
  154. {
  155. int channels = _clip->channels();
  156. sample_t *fbuf = new sample_t[ chunksize * channels ];
  157. size_t len;
  158. int i;
  159. for ( i = 0; i < npeaks; ++i )
  160. {
  161. /* read in a buffer */
  162. len = _clip->read( fbuf, -1, chunksize );
  163. Peak *pk = peaks + (i * channels);
  164. /* get the peak for each channel */
  165. for ( int j = 0; j < channels; ++j )
  166. {
  167. Peak &p = pk[ j ];
  168. p.min = 0;
  169. p.max = 0;
  170. for ( int k = j; k < len * channels; k += channels )
  171. {
  172. if ( fbuf[ k ] > p.max )
  173. p.max = fbuf[ k ];
  174. if ( fbuf[ k ] < p.min )
  175. p.min = fbuf[ k ];
  176. }
  177. }
  178. if ( len < chunksize )
  179. break;
  180. }
  181. delete[] fbuf;
  182. return i;
  183. }
  184. int
  185. Peaks::read_source_peaks ( Peak *peaks, nframes_t s, int npeaks, int chunksize ) const
  186. {
  187. // _clip->open();
  188. _clip->seek( s );
  189. int i = read_source_peaks( peaks, npeaks, chunksize );
  190. // _clip->close();
  191. return i;
  192. }
  193. int
  194. Peaks::read_peaks ( nframes_t s, nframes_t e, int npeaks, int chunksize ) const
  195. {
  196. printf( "reading peaks %d @ %d\n", npeaks, chunksize );
  197. if ( _peakbuf.size < npeaks * _clip->channels() )
  198. {
  199. _peakbuf.size = npeaks * _clip->channels();
  200. // printf( "reallocating peak buffer %li\n", _peakbuf.size );
  201. _peakbuf.buf = (peakdata*)realloc( _peakbuf.buf, sizeof( peakdata ) + (_peakbuf.size * sizeof( Peak )) );
  202. }
  203. assert( s >= 0 );
  204. _peakbuf.offset = s;
  205. _peakbuf.buf->chunksize = chunksize;
  206. /* FIXME: compart to (minimum) peakfile chunk size */
  207. if ( chunksize < 256 )
  208. _peakbuf.len = read_source_peaks( _peakbuf.buf->data, s, npeaks, chunksize );
  209. else
  210. _peakbuf.len = read_peakfile_peaks( _peakbuf.buf->data, s, npeaks, chunksize );
  211. return _peakbuf.len;
  212. }
  213. /** Return the peak for the range of samples */
  214. /* Peak & */
  215. /* Peaks::peak ( nframes_t start, nframes_t end ) const */
  216. /* { */
  217. /* /\* Is there a better way to return this? *\/ */
  218. /* static Peak p; */
  219. /* start = (start - _peakbuf.offset) / _peakbuf.buf->chunksize; */
  220. /* end = (end - _peakbuf.offset) / _peakbuf.buf->chunksize; */
  221. /* if ( end > _peakbuf.len ) */
  222. /* end = _peakbuf.len; */
  223. /* downsample( _peakbuf.buf->data, start, end, &p.max, &p.min ); */
  224. /* return p; */
  225. /* } */
  226. bool
  227. Peaks::open ( void )
  228. {
  229. const char *filename = _clip->name();
  230. int fd;
  231. if ( ! current() )
  232. /* Build peaks asyncronously */
  233. if ( ! fork() )
  234. exit( make_peaks( 256 ) );
  235. if ( ( fd = ::open( peakname( filename ), O_RDONLY ) ) < 0 )
  236. return false;
  237. {
  238. struct stat st;
  239. fstat( fd, &st );
  240. _len = st.st_size;
  241. }
  242. ::close( fd );
  243. _len = (_len - sizeof( int )) / sizeof( Peak );
  244. return true;
  245. }
  246. /** returns false if peak file for /filename/ is out of date */
  247. bool
  248. Peaks::current ( void ) const
  249. {
  250. int sfd, pfd;
  251. if ( ( sfd = ::open( _clip->name(), O_RDONLY ) ) < 0 )
  252. return true;
  253. if ( ( pfd = ::open( peakname( _clip->name() ), O_RDONLY ) ) < 0 )
  254. return false;
  255. struct stat sst, pst;
  256. fstat( sfd, &sst );
  257. fstat( pfd, &pst );
  258. close( sfd );
  259. close( pfd );
  260. return sst.st_mtime <= pst.st_mtime;
  261. }
  262. /* FIXME: we need to work out a way to run this in another thread and
  263. possibly stream back the data to the GUI */
  264. /** build peaks file for /filename/ if necessary */
  265. bool
  266. Peaks::make_peaks ( int chunksize )
  267. {
  268. const char *filename = _clip->name();
  269. if ( current() )
  270. return true;
  271. _clip->seek( 0 );
  272. /* if ( ! _clip->open() ) */
  273. /* return false; */
  274. FILE *fp = fopen( peakname( filename ), "w" );
  275. if ( fp == NULL )
  276. {
  277. // _clip->close();
  278. return false;
  279. }
  280. /* /\* write chunksize first *\/ */
  281. /* fwrite( &chunksize, sizeof( int ), 1, fp ); */
  282. Peak peaks[ _clip->channels() ];
  283. size_t len;
  284. do {
  285. len = read_source_peaks( peaks, 1, chunksize );
  286. fwrite( peaks, sizeof( peaks ), 1, fp );
  287. /* FIXME: GUI code shouldn't be here! */
  288. // Fl::check();
  289. }
  290. while ( len );
  291. // _clip->close();
  292. fclose( fp );
  293. return true;
  294. }
  295. /** return normalization factor for range of samples from /start/ to
  296. /end/ (uses known peak data if possible */
  297. /* float */
  298. /* Peaks::normalization_factor( float fpp, nframes_t start, nframes_t end ) const */
  299. /* { */
  300. /* float s; */
  301. /* // fill_buffer( fpp, start, end ); */
  302. /* /\* if ( end - start < _peaks->chunksize * 4 ) *\/ */
  303. /* /\* fill_buffer( _clip->length() / 4, start, end ); *\/ */
  304. /* /\* else *\/ */
  305. /* /\* fill_buffer( _clip->length(), start, end ); *\/ */
  306. /* Peak p = peak( start, end ); */
  307. /* s = 1.0f / fabs( p.max ); */
  308. /* if ( s * p.min < -1.0 ) */
  309. /* s = 1.0f / fabs( p.min ); */
  310. /* return s; */
  311. /* } */
  312. Peak_Writer::Peak_Writer ( const char *filename, int chunksize, int channels )
  313. {
  314. _channels = channels;
  315. _chunksize = chunksize;
  316. _index = 0;
  317. _peak = new Peak[ channels ];
  318. memset( _peak, 0, sizeof( Peak ) * channels );
  319. if ( ! ( _fp = fopen( peakname( filename ), "w" ) ) )
  320. /* error! */;
  321. // write_header();
  322. }
  323. Peak_Writer::~Peak_Writer ( )
  324. {
  325. fclose( _fp );
  326. delete _peak;
  327. }
  328. void
  329. Peak_Writer::write_header ( void )
  330. {
  331. fprintf( _fp, "NON-PEAKS%2d%2d", VERSION_MAJOR, VERSION_MINOR );
  332. int data[] = { _chunksize, _channels, sizeof( Peak ) };
  333. int size = sizeof( data );
  334. fwrite( &size, sizeof( size ), 1, _fp );
  335. fwrite( &data, sizeof( data ), 1, _fp );
  336. }
  337. /** append peaks for samples in /buf/ to peakfile */
  338. void
  339. Peak_Writer::write ( sample_t *buf, nframes_t nframes )
  340. {
  341. for ( ; nframes--; ++_index, buf += _channels )
  342. {
  343. for ( int j = 0; j < _channels; ++j )
  344. {
  345. Peak *p = _peak + j;
  346. if ( *buf > p->max )
  347. p->max = *buf;
  348. if ( *buf < p->min )
  349. p->min = *buf;
  350. }
  351. if ( _index == _chunksize - 1 )
  352. {
  353. fwrite( _peak, sizeof( Peak ), _channels, _fp );
  354. memset( _peak, 0, sizeof( Peak ) * _channels );
  355. _index = 0;
  356. }
  357. }
  358. }