diff options
| -rw-r--r-- | src/audiocache.cc | 27 | ||||
| -rw-r--r-- | src/drumgizmo.cc | 155 | ||||
| -rw-r--r-- | src/drumgizmo.h | 1 | ||||
| -rw-r--r-- | src/events.h | 12 | ||||
| -rw-r--r-- | test/dgreftest/compareoutputengine.cc | 21 | ||||
| -rw-r--r-- | test/dgreftest/compareoutputengine.h | 2 | ||||
| -rw-r--r-- | test/dgreftest/dgreftest.cc | 24 | 
7 files changed, 128 insertions, 114 deletions
| diff --git a/src/audiocache.cc b/src/audiocache.cc index 2e9eaf8..a2d26d9 100644 --- a/src/audiocache.cc +++ b/src/audiocache.cc @@ -152,8 +152,6 @@ sample_t* AudioCache::open(const AudioFile& file,  sample_t* AudioCache::next(cacheid_t id, std::size_t& size)  { -	size = framesize; -  	if(id == CACHE_DUMMYID)  	{  		settings.number_of_underruns.fetch_add(1); @@ -165,19 +163,14 @@ sample_t* AudioCache::next(cacheid_t id, std::size_t& size)  	if(c.preloaded_samples)  	{ -  		// We are playing from memory:  		if(c.localpos < c.preloaded_samples_size)  		{  			sample_t* s = c.preloaded_samples + c.localpos; +			// If only a partial frame is returned. Reflect this in the size +			size = std::min(size, c.preloaded_samples_size - c.localpos); -			if((c.localpos + framesize) > c.preloaded_samples_size) -			{ -				// Only a partial frame is returned. Reflect this in the size -				size = c.preloaded_samples_size - c.localpos; -			} - -			c.localpos += framesize; +			c.localpos += size;  			return s;  		} @@ -186,7 +179,6 @@ sample_t* AudioCache::next(cacheid_t id, std::size_t& size)  	}  	else  	{ -  		// We are playing from cache:  		if(c.localpos < chunk_size)  		{ @@ -194,13 +186,15 @@ sample_t* AudioCache::next(cacheid_t id, std::size_t& size)  			{  				// Just return silence.  				settings.number_of_underruns.fetch_add(1); -				c.localpos += framesize; // Skip these samples so we don't loose sync. +				c.localpos += size; // Skip these samples so we don't loose sync.  				assert(nodata);  				return nodata;  			}  			sample_t* s = c.front + c.localpos; -			c.localpos += framesize; +			// If only a partial frame is returned. Reflect this in the size +			size = std::min(size, chunk_size - c.localpos); +			c.localpos += size;  			return s;  		}  	} @@ -210,7 +204,7 @@ sample_t* AudioCache::next(cacheid_t id, std::size_t& size)  	{  		// Just return silence.  		settings.number_of_underruns.fetch_add(1); -		c.localpos += framesize; // Skip these samples so we don't loose sync. +		c.localpos += size; // Skip these samples so we don't loose sync.  		assert(nodata);  		return nodata;  	} @@ -219,7 +213,7 @@ sample_t* AudioCache::next(cacheid_t id, std::size_t& size)  	std::swap(c.front, c.back);  	// Next time we go here we have already read the first frame. -	c.localpos = framesize; +	c.localpos = size;  	c.pos += chunk_size; @@ -239,7 +233,6 @@ sample_t* AudioCache::next(cacheid_t id, std::size_t& size)  	// We should always have a front buffer at this point.  	assert(c.front); -  	return c.front;  } @@ -266,8 +259,6 @@ void AudioCache::close(cacheid_t id)  void AudioCache::setFrameSize(std::size_t framesize)  { -	DEBUG(cache, "%s\n", __PRETTY_FUNCTION__); -  	// Make sure the event handler thread is stalled while we set the framesize  	// state.  	std::lock_guard<AudioCacheEventHandler> event_handler_lock(event_handler); diff --git a/src/drumgizmo.cc b/src/drumgizmo.cc index 2d3e410..81db5c5 100644 --- a/src/drumgizmo.cc +++ b/src/drumgizmo.cc @@ -93,12 +93,6 @@ void DrumGizmo::setFrameSize(size_t framesize)  		this->framesize = framesize; -		// Remove all active events as they are cached using the old framesize. -		for(std::size_t ch = 0; ch < MAX_NUM_CHANNELS; ++ch) -		{ -			activeevents[ch].clear(); -		} -  		// Update framesize in drumkitloader and cachemanager:  		loader.setFrameSize(framesize);  		audio_cache.setFrameSize(framesize); @@ -240,11 +234,69 @@ bool DrumGizmo::run(size_t pos, sample_t *samples, size_t nsamples)  	return true;  } -#undef SSE // SSE broken for now ... so disable it. -#ifdef SSE -#define N 8 -typedef float vNsf __attribute__ ((vector_size(sizeof(sample_t)*N))); -#endif/*SSE*/ +void DrumGizmo::renderSampleEvent(EventSample& evt, int pos, sample_t *s, std::size_t sz) +{ +	size_t n = 0; // default start point is 0. + +	// If we are not at offset 0 in current buffer: +	if(evt.offset > (size_t)pos) +	{ +		n = evt.offset - pos; +	} + +	size_t end = sz; // default end point is the end of the buffer. + +	// Find the end point intra-buffer +	if((evt.t + end - n) > evt.sample_size) +	{ +		end = evt.sample_size - evt.t + n; +	} + +	// This should not be necessary but make absolutely sure that we do +	// not write over the end of the buffer. +	if(end > sz) +	{ +		end = sz; +	} + +	size_t t = 0; // Internal buffer counter + +repeat: +	float scale = 1.0f; +	for(; (n < end) && (t < (evt.buffer_size - evt.buffer_ptr)); ++n) +	{ +		assert(n >= 0); +		assert(n < sz); + +		assert(t >= 0); +		assert(t < evt.buffer_size - evt.buffer_ptr); + +		if(evt.rampdownInProgress() && evt.rampdown_count > 0) +		{ +			scale = std::min((float)evt.rampdown_count/evt.ramp_length, 1.f); +			evt.rampdown_count--; +		} + +		s[n] += evt.buffer[evt.buffer_ptr + t] * evt.scale * scale; +		++t; +	} + +	// Add internal buffer counter to "global" event counter. +	evt.t += t;//evt.buffer_size; +	evt.buffer_ptr += t; + +	if(n != sz && evt.t < evt.sample_size) +	{ +		evt.buffer_size = sz - n;// Hint new size + +		// More samples needed for current buffer +		evt.buffer = audio_cache.next(evt.cache_id, evt.buffer_size); + +		evt.buffer_ptr = 0; +		t = 0; +		goto repeat; +	} +}  void DrumGizmo::getSamples(int ch, int pos, sample_t* s, size_t sz)  { @@ -260,7 +312,8 @@ void DrumGizmo::getSamples(int ch, int pos, sample_t* s, size_t sz)  		Event* event = *i;  		Event::type_t type = event->getType(); -		switch(type) { +		switch(type) +		{  		case Event::sample:  			{  				EventSample& evt = *static_cast<EventSample*>(event); @@ -272,9 +325,9 @@ void DrumGizmo::getSamples(int ch, int pos, sample_t* s, size_t sz)  					break;  				} -				// Don't handle event now is is scheduled for a future iteration?  				if(evt.offset > (pos + sz))  				{ +					// Don't handle event now. It is scheduled for a future iteration.  					continue;  				} @@ -290,86 +343,24 @@ void DrumGizmo::getSamples(int ch, int pos, sample_t* s, size_t sz)  					}  					evt.buffer_size = initial_chunksize; +					evt.sample_size = af.size;  				}  				{  					std::lock_guard<std::mutex> guard(af.mutex); -					size_t n = 0; // default start point is 0. - -					// If we are not at offset 0 in current buffer: -					if(evt.offset > (size_t)pos) -					{ -						n = evt.offset - pos; -					} - -					size_t end = sz; // default end point is the end of the buffer. - -					// Find the end point intra-buffer -					if((evt.t + end - n) > af.size) -					{ -						end = af.size - evt.t + n; -					} +					renderSampleEvent(evt, pos, s, sz); -					// This should not be necessary but make absolutely sure that we do -					// not write over the end of the buffer. -					if(end > sz) +					if((evt.t >= evt.sample_size) || (evt.rampdown_count == 0))  					{ -						end = sz; -					} - -					size_t t = 0; // Internal buffer counter -					if(!evt.rampdownInProgress()) -					{ -#ifdef SSE -						size_t optend = ((end - n) / N) * N + n; - -						// Force source addr to be 16 byte aligned... -						// (might skip 1 or 2 samples) -						while((size_t)&evt.buffer[t] % 16) -						{ -							++t; -						} - -						for(; (n < optend) && (t < evt.buffer_size); n += N) -						{ -							*(vNsf*)&(s[n]) += *(vNsf*)&(evt.buffer[t]) * evt.scale; -							t += N; -						} -#endif -						for(; (n < end) && (t < evt.buffer_size); ++n) -						{ -							assert(n >= 0); -							assert(n < sz); - -							assert(t >= 0); -							assert(t < evt.buffer_size); - -							s[n] += evt.buffer[t] * evt.scale; -							++t; -						} -					} -					else -					{ // Ramp down in progress. -						for(; (n < end) && (t < evt.buffer_size) && evt.rampdown_count; ++n) -						{ -							float scale = std::min((float)evt.rampdown_count/evt.ramp_length, 1.f); -							s[n] += evt.buffer[t] * evt.scale * scale; -							++t; -							evt.rampdown_count--; -						} +						removeevent = true;  					} -					// Add internal buffer counter to "global" event counter. -					evt.t += evt.buffer_size; - -					if((evt.t < af.size) && (evt.rampdown_count != 0)) +					if(evt.buffer_ptr >= evt.buffer_size && removeevent == false)  					{ +						evt.buffer_size = sz;  						evt.buffer = audio_cache.next(evt.cache_id, evt.buffer_size); -					} -					else -					{ -						removeevent = true; +						evt.buffer_ptr = 0;  					}  					if(removeevent) diff --git a/src/drumgizmo.h b/src/drumgizmo.h index 562e2ba..0f2c20e 100644 --- a/src/drumgizmo.h +++ b/src/drumgizmo.h @@ -56,6 +56,7 @@ public:  	bool run(size_t pos, sample_t *samples, size_t nsamples);  	void stop(); +	void renderSampleEvent(EventSample& evt, int pos, sample_t *s, std::size_t sz);  	void getSamples(int ch, int pos, sample_t *s, size_t sz);  	//! Get the current engine latency in samples. diff --git a/src/events.h b/src/events.h index b78dd79..c28283e 100644 --- a/src/events.h +++ b/src/events.h @@ -31,8 +31,6 @@  #include <string>  #include <mutex> -#include <sndfile.h> -  #include "audiofile.h"  #include "audio.h"  #include "audiocache.h" @@ -62,7 +60,8 @@ public:  	timepos_t offset; //< Global position (ie. not relative to buffer)  }; -class EventSample : public Event +class EventSample +	: public Event  {  public:  	EventSample(channel_t c, float g, AudioFile* af, @@ -91,10 +90,12 @@ public:  	cacheid_t cache_id;  	sample_t* buffer; -	size_t buffer_size; +	std::size_t buffer_size; +	std::size_t buffer_ptr{0}; //< Internal pointer into the current buffer +	std::size_t sample_size{0}; //< Total number of audio samples in this sample.  	float gain; -	unsigned int t; +	unsigned int t; //< Internal sample position.  	AudioFile* file;  	std::string group;  	void* instrument; @@ -118,4 +119,3 @@ private:  	std::multimap<timepos_t, Event*> queue;  	std::mutex mutex;  }; - diff --git a/test/dgreftest/compareoutputengine.cc b/test/dgreftest/compareoutputengine.cc index 33dfe2a..04145b0 100644 --- a/test/dgreftest/compareoutputengine.cc +++ b/test/dgreftest/compareoutputengine.cc @@ -33,6 +33,7 @@ CompareOutputEngine::CompareOutputEngine()  	, info{}  	, file{"output"}  { +	info = {};  	info.samplerate = 44100;  	info.channels = 1;  	info.format = SF_FORMAT_WAV | SF_FORMAT_FLOAT; @@ -44,9 +45,9 @@ CompareOutputEngine::~CompareOutputEngine()  	sf_close(handle);  } -bool CompareOutputEngine::init(const Channels& data) +bool CompareOutputEngine::init(const Channels& channels)  { -	info.channels = data.size(); +	info.channels = channels.size();  	handle = sf_open(file.c_str(), SFM_READ, &info);  	if(handle == nullptr) @@ -116,8 +117,11 @@ void CompareOutputEngine::run(int ch, sample_t* samples, size_t nsamples)  void CompareOutputEngine::post(size_t nsamples)  { -	sample_t ref_buffer[sizeof(buffer) / sizeof(sample_t)]; -	sf_readf_float(handle, ref_buffer, nsamples); +	nsamples = sf_readf_float(handle, ref_buffer, nsamples); +	if(nsamples == 0) +	{ +		return; +	}  	for(std::size_t i = 0; i < nsamples; ++i)  	{ @@ -126,10 +130,17 @@ void CompareOutputEngine::post(size_t nsamples)  			if(buffer[i * info.channels + ch] != ref_buffer[i * info.channels + ch])  			{  				++diff_samples; + +				// Use this to quit on first bad sample. +				//std::cerr << "ch: " << ch << ", pos: " << pos + i << +				//	" expected: " << ref_buffer[i * info.channels + ch] << +				//	" got: " << buffer[i * info.channels + ch] << std::endl; +				//exit(1); +  			}  		}  	} - +	pos += nsamples;  }  size_t CompareOutputEngine::getSamplerate() const diff --git a/test/dgreftest/compareoutputengine.h b/test/dgreftest/compareoutputengine.h index a82116c..89a3a83 100644 --- a/test/dgreftest/compareoutputengine.h +++ b/test/dgreftest/compareoutputengine.h @@ -53,4 +53,6 @@ private:  	std::string file;  	sample_t buffer[4096 * 16];  	std::size_t diff_samples{0}; +	sample_t ref_buffer[sizeof(buffer) / sizeof(sample_t)]; +	size_t pos{0};  }; diff --git a/test/dgreftest/dgreftest.cc b/test/dgreftest/dgreftest.cc index ea38091..a4eb897 100644 --- a/test/dgreftest/dgreftest.cc +++ b/test/dgreftest/dgreftest.cc @@ -135,14 +135,32 @@ int main(int argc, char* argv[])  	size_t nsamples = oe->getBufferSize();  	sample_t *samples = (sample_t *)malloc(nsamples * sizeof(sample_t)); -	drumgizmo.setFrameSize(oe->getBufferSize()); +	drumgizmo.setFrameSize(nsamples);  	ie.start();  	oe->start(); -	while(drumgizmo.run(pos, samples, nsamples) == true) +	size_t framesize = nsamples; +	int dir = -1; +	while(drumgizmo.run(pos, samples, framesize) == true)  	{ -		pos += nsamples; +		pos += framesize; + +		framesize += dir; + +		if(framesize < 1) +		{ +			framesize = 1; +			dir = 1; +		} + +		if(framesize >= nsamples) +		{ +			framesize = nsamples; +			dir = -1; +		} + +		drumgizmo.setFrameSize(framesize);  	}  	ie.stop(); | 
