diff options
author | Bent Bisballe Nyeng <deva@aasimon.org> | 2014-09-08 20:48:38 +0200 |
---|---|---|
committer | Bent Bisballe Nyeng <deva@aasimon.org> | 2014-09-08 20:48:38 +0200 |
commit | 7776aa97fc1c69a8f28ba4bab7387fb96be9a6e4 (patch) | |
tree | 8e23cfbfe7e93bdfad4421ccb0ec8c280a0b43ed /src/player.cc | |
parent | 56f5965ffa2538dfa482ae9460e9579b4a04f8fb (diff) |
Import dgedit from drumgizmo repository (split into its own project).
Diffstat (limited to 'src/player.cc')
-rw-r--r-- | src/player.cc | 190 |
1 files changed, 190 insertions, 0 deletions
diff --git a/src/player.cc b/src/player.cc new file mode 100644 index 0000000..3a2bfd2 --- /dev/null +++ b/src/player.cc @@ -0,0 +1,190 @@ +/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ +/*************************************************************************** + * player.cc + * + * Tue Apr 15 10:34:18 CEST 2014 + * Copyright 2014 Bent Bisballe Nyeng + * deva@aasimon.org + ****************************************************************************/ + +/* + * This file is part of DrumGizmo. + * + * DrumGizmo 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 2 of the License, or + * (at your option) any later version. + * + * DrumGizmo 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 DrumGizmo; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA. + */ +#include "player.h" + +#include <math.h> + +#define BUFSZ 512 + +Player::Player() +{ + peak = 0; + pos = 0; + gain_scalar = 1.0; + pcm_data = NULL; + pcm_size = 0; + end = 0; + new_selection = false; + + connect(&report_timer, SIGNAL(timeout()), this, SLOT(reportTimeout())); + report_timer.start(50); // Update 25 times per second + + start(); +} + +Player::~Player() +{ + running = false; // Signal player thread to stop + wait(); // Wait for player thread to stop. +} + +#define _MIN(a, b) (a<b?a:b) +void Player::run() +{ + Selection sel; + + ao_initialize(); + + ao_sample_format sf; + memset(&sf, 0, sizeof(sf)); + sf.bits = 16; + sf.rate = 44100; + sf.channels = 1; + sf.byte_format = AO_FMT_NATIVE; + + dev = ao_open_live(ao_default_driver_id(), &sf, 0); + + running = true; + + short s[BUFSZ]; + while(running) { + + { // Check for new Selection. + QMutexLocker lock(&mutex); + if(new_selection) { + sel = selection; + pos = sel.from; + end = sel_end; + new_selection = false; + } + } + + for(size_t i = 0; i < BUFSZ; i++) { + double sample = 0.0; + size_t p = i + pos; + if(p < sel.to && p < end && p < pcm_size) { + double fade = 1; + if(p < (sel.from + sel.fadein)) { + // Apply linear fade-in + double fp = (double)((int)p - (int)sel.from); + fade = fp / (double)sel.fadeout; + } + + if(p > (sel.to - sel.fadeout)) { + // Apply linear fade-out + double fp = (double)(((int)sel.to - (int)sel.fadeout) - (int)p); + fade = 1 + (fp / (double)sel.fadeout); + } + + sample = pcm_data[p] * fade * gain_scalar; + } + if(fabs(sample) > peak) { + peak = fabs(sample); + } + s[i] = _MIN(sample * SHRT_MAX, SHRT_MAX); + } + + ao_play(dev, (char*)s, BUFSZ * sizeof(short)); + + pos += BUFSZ; + } + + ao_close(dev); + ao_shutdown(); +} + +bool Player::playSelectionDone() +{ + return pos >= sel_end || pos >= selection.to; +} + +void Player::playSelection(Selection s, int len) +{ + { // Enqueue new Selection for player consumation + QMutexLocker lock(&mutex); + + selection = s; + + if(len > 0) sel_end = len; + else sel_end = selection.to - selection.from; + + sel_end += selection.from; + + new_selection = true; + } + + // Wait until player actually consumed the new Selection. + while(new_selection) { + msleep(1); + } +} + +void Player::setGainScalar(double g) +{ + gain_scalar = g; +} + +void Player::setGainDB(double gain_db) +{ + setGainScalar(pow(10, gain_db/ 20.0)); +} + +void Player::reportTimeout() +{ + emit peakUpdate(peak); + emit peakUpdateDB(20 * log10(peak)); + peak = 0.0; + + emit positionUpdate(pos); + peak = 0.0; +} + +void Player::setPcmData(float *data, size_t size) +{ + pcm_data = data; + pcm_size = size; +} + +void Player::setPosition(size_t position) +{ + Selection s; + s.from = position; + s.to = pcm_size; + s.fadein = 0; + s.fadeout = 0; + playSelection(s); +} + +void Player::stop() +{ + Selection s; + s.from = 0; + s.to = 0; + s.fadein = 0; + s.fadeout = 0; + playSelection(s, pos); +} |