Merge pull request #506 from andrewcsmith/patch-2
[supercollider.git] / QtCollider / widgets / soundfileview / filestream.cpp
blob93e2e876048354cadfb72e8f013c7734aba23d2e
1 /************************************************************************
3 * Copyright 2012 Jakob Leben (jakob.leben@gmail.com)
5 * This file is part of SuperCollider Qt GUI.
7 * This program is free software: you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation, either version 3 of the License, or
10 * (at your option) any later version.
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
17 * You should have received a copy of the GNU General Public License
18 * along with this program. If not, see <http://www.gnu.org/licenses/>.
20 ************************************************************************/
22 #include "view.hpp"
24 SoundFileStream::SoundFileStream() : _data(0), _dataSize(0), _dataOffset(0)
27 SoundFileStream::SoundFileStream( SNDFILE *sf, const SF_INFO &info, sf_count_t b, sf_count_t d )
28 : _data(0)
30 load( sf, info, b, d );
33 SoundFileStream::~SoundFileStream()
35 delete[] _data;
38 void SoundFileStream::load( SNDFILE *sf, const SF_INFO &info, sf_count_t beg, sf_count_t dur )
40 delete[] _data;
42 _dataOffset = beg;
43 _dataSize = dur;
45 _data = new short [_dataSize * info.channels];
46 sf_seek( sf, _dataOffset, SEEK_SET);
47 _dataSize = sf_readf_short( sf, _data, _dataSize );
49 _ch = info.channels;
50 _beg = _dataOffset;
51 _dur = _dataSize;
54 bool SoundFileStream::integrate
55 ( int ch, double f_beg, double f_dur,
56 short *minBuffer, short *maxBuffer, float *sumBuf, float *sum2Buf, int bufferSize )
58 bool ok = _data != 0
59 && ch < channels()
60 && ( f_beg >= beginning() )
61 && ( f_beg + f_dur <= beginning() + duration() );
62 if( !ok ) return false;
64 double fpu = f_dur / bufferSize;
65 double f_pos = f_beg - _dataOffset;
66 double f_pos_max = _dataSize;
68 int i;
69 for( i = 0; i < bufferSize; ++i ) {
70 int data_pos = floor(f_pos);
72 // increment position
74 // slower, but error-proof:
75 // f_pos = (double)(i+1) / width() * f_dur + f_beg;
77 // the following is a faster variant, but floating point operations are fallible,
78 // so we need to make sure we stay within the constraints of f_dur;
79 double f_pos1 = f_pos + fpu;
80 if( f_pos1 > f_pos_max ) f_pos1 = f_pos_max;
82 int frame_count = ceil(f_pos1) - data_pos;
84 float frac0 = data_pos + 1.f - f_pos;
85 float frac1 = f_pos1 + 1.f - ceil(f_pos1);
87 // get min, max and sum
88 short *samples = _data + (data_pos * channels()) + ch;
89 short min = SHRT_MAX;
90 short max = SHRT_MIN;
91 float sum = 0.f;
92 float sum2 = 0.f;
93 int f; // frame
94 for( f = 0; f < frame_count; ++f, samples += channels() ){
95 // TODO should we overlap min-max or not here?
96 float sample = *samples;
97 float frac;
98 if( f == 0 ) frac = frac0;
99 else if( f == frame_count - 1 ) frac = frac1;
100 else frac = 1.0;
102 if( sample < min ) min = sample;
103 if( sample > max ) max = sample;
105 sum += sample * frac;
106 sum2 += sample * sample * frac;
109 minBuffer[i] = min;
110 maxBuffer[i] = max;
111 sumBuf[i] = sum;
112 sum2Buf[i] = sum2;
114 f_pos = f_pos1;
117 return true;
120 bool SoundFileStream::displayData
121 ( int ch, double f_beg, double f_dur,
122 short *minBuffer, short *maxBuffer, short *minRMS, short *maxRMS, int bufferSize )
124 bool ok = _data != 0
125 && ch < channels()
126 && ( f_beg >= beginning() )
127 && ( f_beg + f_dur <= beginning() + duration() );
128 if( !ok ) return false;
130 double fpu = f_dur / bufferSize;
131 double f_pos = f_beg - _dataOffset;
132 double f_pos_max = _dataSize;
134 short min = SHRT_MAX;
135 short max = SHRT_MIN;
137 double D_SHRT_MAX = (double) SHRT_MAX;
138 double D_SHRT_MIN = (double) SHRT_MIN;
140 int i;
141 for( i = 0; i < bufferSize; ++i ) {
142 int data_pos = floor(f_pos);
144 // increment position
146 // slower, but error-proof:
147 // f_pos = (double)(i+1) / width() * f_dur + f_beg;
149 // the following is a faster variant, but floating point operations are fallible,
150 // so we need to make sure we stay within the constraints of f_dur;
151 double f_pos1 = f_pos + fpu;
152 if( f_pos1 > f_pos_max ) f_pos1 = f_pos_max;
154 int frame_count = ceil(f_pos1) - data_pos;
156 float frac0 = data_pos + 1.f - f_pos;
157 float frac1 = f_pos1 + 1.f - ceil(f_pos1);
159 // get min, max and sum
160 short *samples = _data + (data_pos * channels()) + ch;
162 float sum = 0.f;
163 float sum2 = 0.f;
164 int f; // frame
165 for( f = 0; f < frame_count; ++f, samples += channels() ){
166 // TODO should we overlap min-max or not here?
167 float sample = *samples;
168 float frac;
169 if( f == 0 ) frac = frac0;
170 else if( f == frame_count - 1 ) frac = frac1;
171 else frac = 1.0;
173 if( sample < min ) min = sample;
174 if( sample > max ) max = sample;
176 sum += sample * frac;
177 sum2 += sample * sample * frac;
180 double n = fpu;
181 double avg = sum / n;
182 double stdDev = sqrt( abs((sum2 - (sum*avg) ) / n) );
184 minBuffer[i] = min;
185 maxBuffer[i] = max;
186 minRMS[i] = std::max(D_SHRT_MIN, std::min(D_SHRT_MAX, avg - stdDev ));
187 maxRMS[i] = std::max(D_SHRT_MIN, std::min(D_SHRT_MAX, avg + stdDev ));
189 f_pos = f_pos1;
190 min = maxBuffer[i];
191 max = minBuffer[i];
194 return true;
197 short *SoundFileStream::rawFrames( int ch, sf_count_t b, sf_count_t d, bool *interleaved )
199 if( ch > channels() || b < _dataOffset || b + d > _dataOffset + _dataSize ) return 0;
200 *interleaved = true;
201 sf_count_t offset = (b - _dataOffset) * channels() + ch;
202 return ( _data + offset );