123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205 |
- /*
- This file is part of QTau
- Copyright (C) 2013-2018 Tobias "Tomoko" Platen <tplaten@posteo.de>
- Copyright (C) 2013 digited <https://github.com/digited>
- Copyright (C) 2010-2013 HAL@ShurabaP <https://github.com/haruneko>
- QTau is free software: you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation, either version 3 of the License, or
- (at your option) any later version.
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
- You should have received a copy of the GNU General Public License
- along with this program. If not, see <http://www.gnu.org/licenses/>.
- SPDX-License-Identifier: GPL-3.0+
- */
- #include "audio/outputbuffer.h"
- #include <stdio.h>
- #include <string.h>
- #include <unistd.h>
- #include <stdint.h>
- #include <sys/time.h>
- #define __devloglevel__ 4
- #define debugperf 0
- #define debugperf2 0
- uint32_t getTime() {
- struct timeval tv;
- gettimeofday(&tv, NULL);
- uint32_t ret = static_cast<uint32_t>(tv.tv_usec / 1000 + tv.tv_sec * 1000);
- return ret;
- }
- OutputBuffer::OutputBuffer(JackAudio* jack)
- {
- _buffersize=64*1024;
- _jackSamplerate = jack->getSamplerate();
- _ringbuffer = jack_ringbuffer_create(_buffersize);
- _sndfile = nullptr;
- _datacount=0;
- start();
- }
- void OutputBuffer::scheduleSynth(ISynth *synth)
- {
- if(_scheduledSynth) return;
- _datacount = 0;
- _runtime = 0;
- jack_ringbuffer_reset(_ringbuffer);
- open("/tmp/test.wav",44100);
- _scheduledSynth=synth;
- }
- void OutputBuffer::run()
- {
- int data_size = 1024*2;
- float* data = new float[data_size];
- uint32_t lasttime = getTime();
- while(1)
- {
- if(_scheduledSynth)
- {
- int end = _scheduledSynth->readData(data,data_size);
- if(end==0)
- {
- _scheduledSynth->readData(nullptr,0);
- _scheduledSynth= nullptr;
- close();
- continue;
- }
- int writespace = jack_ringbuffer_write_space(_ringbuffer);
- int size2 = data_size*sizeof(float);
- int sleepcount=0;
- while(writespace<2*size2)
- {
- if(!_playbackIsStable) emit startPlayback();
- _playbackIsStable = true;
- usleep(1000);
- sleepcount++;
- writespace = jack_ringbuffer_write_space(_ringbuffer);
- }
- uint32_t currenttime = getTime();
- uint32_t timedelta = currenttime-lasttime;
- lasttime=currenttime;
- if(debugperf) DEVLOG_DEBUG("sleepcount "+STR(sleepcount)+" writespace "+STR(writespace)+" timedelta "+STR(timedelta));
- _runtime += timedelta;
- uint32_t timedelta_max = (int)(data_size*1000/44100);
- if(debugperf2) if(timedelta>timedelta_max) DEVLOG_DEBUG("timedelta_max "+STR(timedelta_max)+" timedelta "+STR(timedelta-sleepcount));
- jack_ringbuffer_write(_ringbuffer,(char*)data,size2);
- sf_write_float(_sndfile,data,data_size);
- }
- else
- {
- usleep(20000); //nothing to do
- }
- }
- }
- //on synth start
- void OutputBuffer::open(QString fileName,int samplerate){
- if(_sndfile) sf_close(_sndfile);
- SF_INFO info;
- memset(&info,0,sizeof(info));
- info.format = SF_FORMAT_WAV | SF_FORMAT_PCM_16;
- info.samplerate = samplerate;
- info.channels = 1;
- _sndfile = sf_open(fileName.toUtf8().data(),SFM_WRITE,&info);
- if(_jackSamplerate!=samplerate)
- {
- DEVLOG_ERROR("resampler TODO\n");
- exit(1);
- }
- }
- void OutputBuffer::openReadFile(QString fileName)
- {
- SF_INFO info;
- memset(&info,0,sizeof(info));
- _sndfile = sf_open(fileName.toUtf8().data(),SFM_READ,&info);
- _offline = true;
- }
- //on synth end
- void OutputBuffer::close()
- {
- if(_sndfile) sf_close(_sndfile);
- _sndfile = nullptr;
- jack_ringbuffer_reset(_ringbuffer);
- _datacount = 0;
- }
- //other thread -- copy engine
- void OutputBuffer::readData(float *data, int size)
- {
- if(_offline && _sndfile)
- {
- int count = sf_readf_float(_sndfile,data,size);
- if(count==0)
- {
- DEVLOG_DEBUG("offline mode: stop playback");
- emit stopPlayback();
- close();
- }
- return;
- }
- //if(!_playbackIsStable) return; //do nothing
- unsigned int data_size = (unsigned int)size*sizeof(float);
- memset(data,0,data_size);
- unsigned int readspace = jack_ringbuffer_read_space(_ringbuffer);
- float filled = readspace*1.0/_buffersize;
- if(filled<0.5 && debugperf) DEVLOG_DEBUG("reading data "+STR(filled));
- if(!_playbackIsStable) return;
- if(readspace>=data_size)
- {
- jack_ringbuffer_read(_ringbuffer,(char*)data,data_size);
- }
- else
- {
- if(_scheduledSynth)
- {
- if(debugperf) DEVLOG_DEBUG("XRUN - cannot read from buffer");
- _xruncount++;
- }
- else
- {
- if(_playbackIsStable)
- {
- DEVLOG_DEBUG("end reached xruncount="+STR(_xruncount)+" cputime="+STR(_runtime));
- stopPlayback();
- _playbackIsStable=false;
- }
- }
- }
- }
- void OutputBuffer::reset()
- {
- jack_ringbuffer_reset(_ringbuffer);
- _datacount = 0;
- }
|