Fix audio memory leak and fix windows distortion (#402)

* Fix audio memory leak and fix windows distortion

* Fix play button resetting
This commit is contained in:
Jeremy Bullock 2020-10-22 10:43:35 -06:00 committed by GitHub
parent 6954f4d14c
commit c57e297804
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
12 changed files with 165 additions and 2326 deletions

File diff suppressed because it is too large Load diff

View file

@ -5,6 +5,7 @@
#include "toonz/txshcolumn.h" #include "toonz/txshcolumn.h"
#include "toonz/txshcell.h" #include "toonz/txshcell.h"
#include "toonz/txshsoundlevel.h"
#include "tsound.h" #include "tsound.h"
#include <QList> #include <QList>
@ -23,7 +24,69 @@
//============================================================================= //=============================================================================
// forward declarations // forward declarations
class TFilePath; class TFilePath;
class ColumnLevel;
//=============================================================================
// ColumnLevel
//=============================================================================
class ColumnLevel {
TXshSoundLevelP m_soundLevel;
/*!Offsets: in frames. Start offset is a positive number.*/
int m_startOffset;
/*!Offsets: in frames. End offset is a positive number(to subtract to..).*/
int m_endOffset;
//! Starting frame in the timeline
int m_startFrame;
//! frameRate
double m_fps;
public:
ColumnLevel(TXshSoundLevel* soundLevel = 0, int startFrame = -1,
int startOffset = -1, int endOffset = -1, double fps = -1);
~ColumnLevel();
ColumnLevel* clone() const;
//! Overridden from TXshLevel
TXshSoundLevel* getSoundLevel() const { return m_soundLevel.getPointer(); }
void setSoundLevel(TXshSoundLevelP level) { m_soundLevel = level; }
void loadData(TIStream& is);
void saveData(TOStream& os);
void setStartOffset(int value);
int getStartOffset() const { return m_startOffset; }
void setEndOffset(int value);
int getEndOffset() const { return m_endOffset; }
void setOffsets(int startOffset, int endOffset);
//! Return the starting frame without offsets.
void setStartFrame(int frame) { m_startFrame = frame; }
int getStartFrame() const { return m_startFrame; }
//! Return the ending frame without offsets.
int getEndFrame() const;
//! Return frame count without offset.
int getFrameCount() const;
//! Return frame count with offset.
int getVisibleFrameCount() const;
//! Return start frame with offset.
int getVisibleStartFrame() const;
//! Return last frame with offset.
int getVisibleEndFrame() const;
//! Updates m_startOfset and m_endOffset.
void updateFrameRate(double newFrameRate);
void setFrameRate(double fps) { m_fps = fps; }
};
//============================================================================= //=============================================================================
//! The TXshSoundColumn class provides a sound column in xsheet and allows its //! The TXshSoundColumn class provides a sound column in xsheet and allows its
@ -75,6 +138,7 @@ public:
int getFirstRow() const override; int getFirstRow() const override;
const TXshCell &getCell(int row) const override; const TXshCell &getCell(int row) const override;
TXshCell getSoundCell(int row);
void getCells(int row, int rowCount, TXshCell cells[]) override; void getCells(int row, int rowCount, TXshCell cells[]) override;
bool setCell(int row, const TXshCell &cell) override; bool setCell(int row, const TXshCell &cell) override;

View file

@ -856,28 +856,32 @@ QString TTool::updateEnabled(int rowIndex, int columnIndex) {
// find the nearest level before it // find the nearest level before it
if (levelType == NO_XSHLEVEL && if (levelType == NO_XSHLEVEL &&
!m_application->getCurrentFrame()->isEditingLevel()) { !m_application->getCurrentFrame()->isEditingLevel()) {
if (!column || (column && !column->getSoundColumn())) {
TXshCell cell = xsh->getCell(rowIndex, columnIndex); TXshCell cell = xsh->getCell(rowIndex, columnIndex);
xl = cell.isEmpty() ? 0 : (TXshLevel *)(&cell.m_level); xl = cell.isEmpty() ? 0 : (TXshLevel*)(&cell.m_level);
sl = cell.isEmpty() ? 0 : cell.getSimpleLevel(); sl = cell.isEmpty() ? 0 : cell.getSimpleLevel();
levelType = cell.isEmpty() ? NO_XSHLEVEL : cell.m_level->getType(); levelType = cell.isEmpty() ? NO_XSHLEVEL : cell.m_level->getType();
} }
}
if (Preferences::instance()->isAutoCreateEnabled()) { if (Preferences::instance()->isAutoCreateEnabled()) {
// If not in Level editor, let's use our current cell from the xsheet to // If not in Level editor, let's use our current cell from the xsheet to
// find the nearest level before it // find the nearest level before it
if (levelType == NO_XSHLEVEL && if (levelType == NO_XSHLEVEL &&
!m_application->getCurrentFrame()->isEditingLevel()) { !m_application->getCurrentFrame()->isEditingLevel()) {
if (!column || (column && !column->getSoundColumn())) {
int r0, r1; int r0, r1;
xsh->getCellRange(columnIndex, r0, r1); xsh->getCellRange(columnIndex, r0, r1);
for (int r = std::min(r1, rowIndex); r > r0; r--) { for (int r = std::min(r1, rowIndex); r > r0; r--) {
TXshCell cell = xsh->getCell(r, columnIndex); TXshCell cell = xsh->getCell(r, columnIndex);
if (cell.isEmpty()) continue; if (cell.isEmpty()) continue;
xl = (TXshLevel *)(&cell.m_level); xl = (TXshLevel*)(&cell.m_level);
sl = cell.getSimpleLevel(); sl = cell.getSimpleLevel();
levelType = cell.m_level->getType(); levelType = cell.m_level->getType();
break; break;
} }
} }
}
// If the current tool does not match the current type, check for // If the current tool does not match the current type, check for
// a version of the same tool that does // a version of the same tool that does

View file

@ -2108,6 +2108,7 @@ void SceneViewer::drawScene() {
args.m_osm = &osm; args.m_osm = &osm;
args.m_xsheetLevel = xsheetLevel; args.m_xsheetLevel = xsheetLevel;
args.m_isPlaying = frameHandle->isPlaying(); args.m_isPlaying = frameHandle->isPlaying();
if (app->getCurrentColumn()->getColumn() && !app->getCurrentColumn()->getColumn()->getSoundColumn())
args.m_currentFrameId = args.m_currentFrameId =
app->getCurrentXsheet() app->getCurrentXsheet()
->getXsheet() ->getXsheet()

View file

@ -49,6 +49,7 @@
#include "toonz/tcamera.h" #include "toonz/tcamera.h"
#include "toonz/preferences.h" #include "toonz/preferences.h"
#include "toonz/fullcolorpalette.h" #include "toonz/fullcolorpalette.h"
#include "toonz/txshsoundcolumn.h"
#include "toonzqt/tabbar.h" #include "toonzqt/tabbar.h"
@ -310,6 +311,8 @@ int TApp::getCurrentImageType() {
} }
TXsheet *xsh = getCurrentXsheet()->getXsheet(); TXsheet *xsh = getCurrentXsheet()->getXsheet();
if (xsh->getColumn(col) && xsh->getColumn(col)->getSoundColumn())
return TImage::VECTOR;
TXshCell cell = xsh->getCell(row, col); TXshCell cell = xsh->getCell(row, col);
if (cell.isEmpty()) { if (cell.isEmpty()) {
int r0, r1; int r0, r1;
@ -357,7 +360,18 @@ void TApp::updateXshLevel() {
int column = m_currentColumn->getColumnIndex(); int column = m_currentColumn->getColumnIndex();
TXsheet *xsheet = m_currentXsheet->getXsheet(); TXsheet *xsheet = m_currentXsheet->getXsheet();
if (xsheet && column >= 0 && frame >= 0 && !xsheet->isColumnEmpty(column)) { bool isSoundColumn = false;
if (xsheet->getColumn(column) &&
xsheet->getColumn(column)->getSoundColumn()) {
isSoundColumn = true;
if (xsheet->getColumn(column)->getSoundColumn()->m_levels.size() > 0) {
xl = static_cast<TXshLevel *>(xsheet->getColumn(column)
->getSoundColumn()
->m_levels.at(0)
->getSoundLevel());
}
} else if (xsheet && column >= 0 && frame >= 0 &&
!xsheet->isColumnEmpty(column)) {
TXshCell cell = xsheet->getCell(frame, column); TXshCell cell = xsheet->getCell(frame, column);
xl = cell.m_level.getPointer(); xl = cell.m_level.getPointer();

View file

@ -645,7 +645,8 @@ void SceneViewerPanel::changeWindowTitle() {
return; return;
} }
TXsheet *xsh = app->getCurrentXsheet()->getXsheet(); TXsheet *xsh = app->getCurrentXsheet()->getXsheet();
TXshCell cell = xsh->getCell(frame, col); TXshCell cell;
if (app->getCurrentColumn()->getColumn() && !app->getCurrentColumn()->getColumn()->getSoundColumn()) cell = xsh->getCell(frame, col);
if (cell.isEmpty()) { if (cell.isEmpty()) {
if (!m_sceneViewer->is3DView()) { if (!m_sceneViewer->is3DView()) {
TAffine aff = m_sceneViewer->getViewMatrix() * TAffine aff = m_sceneViewer->getViewMatrix() *

View file

@ -1415,8 +1415,8 @@ void CellArea::drawSoundCell(QPainter &p, int row, int col, bool isReference) {
} }
TXshCell nextCell; TXshCell nextCell;
nextCell = nextCell = soundColumn->getSoundCell(row + 1); // cell in next frame
m_viewer->getXsheet()->getCell(row + 1, col); // cell in next frame bool isNextEmpty = nextCell.getFrameId().getNumber() < 0;
int frameAdj = m_viewer->getFrameZoomAdjustment(); int frameAdj = m_viewer->getFrameZoomAdjustment();
int frameZoomF = m_viewer->getFrameZoomFactor(); int frameZoomF = m_viewer->getFrameZoomFactor();
@ -1424,13 +1424,11 @@ void CellArea::drawSoundCell(QPainter &p, int row, int col, bool isReference) {
cellRect.adjust(0, 0, -frameAdj, 0); cellRect.adjust(0, 0, -frameAdj, 0);
QRect rect = cellRect.adjusted( QRect rect = cellRect.adjusted(
1, 1, 1, 1,
(!m_viewer->orientation()->isVerticalTimeline() && !nextCell.isEmpty() (!m_viewer->orientation()->isVerticalTimeline() && !isNextEmpty ? 2 : 0),
? 2
: 0),
0); 0);
int maxNumFrame = soundColumn->getMaxFrame() + 1; int maxNumFrame = soundColumn->getMaxFrame() + 1;
int startFrame = soundColumn->getFirstRow(); int startFrame = soundColumn->getFirstRow();
TXshCell cell = soundColumn->getCell(row); TXshCell cell = soundColumn->getSoundCell(row);
if (soundColumn->isCellEmpty(row) || cell.isEmpty() || row > maxNumFrame || if (soundColumn->isCellEmpty(row) || cell.isEmpty() || row > maxNumFrame ||
row < startFrame) { row < startFrame) {
drawFrameSeparator(p, row, col, true); drawFrameSeparator(p, row, col, true);
@ -2948,7 +2946,7 @@ void CellArea::mouseMoveEvent(QMouseEvent *event) {
->getZeraryColumnFx() ->getZeraryColumnFx()
->getZeraryFx() ->getZeraryFx()
->getName()); ->getName());
else if ((!xsh->getCell(row, col).isEmpty() && !isSoundColumn) && // x > 6 && else if ((!isSoundColumn && !xsh->getCell(row, col).isEmpty()) && // x > 6 &&
x < (o->cellWidth() - frameAdj)) { x < (o->cellWidth() - frameAdj)) {
TXshCell cell = xsh->getCell(row, col); TXshCell cell = xsh->getCell(row, col);
TFrameId fid = cell.getFrameId(); TFrameId fid = cell.getFrameId();

View file

@ -2282,8 +2282,12 @@ void ColumnArea::mousePressEvent(QMouseEvent *event) {
TSoundTrackP sTrack = s->getCurrentPlaySoundTruck(); TSoundTrackP sTrack = s->getCurrentPlaySoundTruck();
interval = sTrack->getDuration() * 1000 + 300; interval = sTrack->getDuration() * 1000 + 300;
} }
if (s->isPlaying() && interval > 0) if (s->isPlaying() && interval > 0) {
QTimer::singleShot(interval, this, SLOT(update())); QTimer::singleShot(interval, this, [this, s] {
if (s && s->isPlaying()) s->stop();
update();
});
}
} }
update(); update();
} else if (!o->flag(PredefinedFlag::CONFIG_AREA_VISIBLE) && } else if (!o->flag(PredefinedFlag::CONFIG_AREA_VISIBLE) &&

View file

@ -128,10 +128,15 @@ void XsheetViewer::getColumnColor(QColor &color, QColor &sideColor, int index,
xsh->getCellRange(index, r0, r1); xsh->getCellRange(index, r0, r1);
if (0 <= r0 && r0 <= r1) { if (0 <= r0 && r0 <= r1) {
// column color depends on the level type in the top-most occupied cell // column color depends on the level type in the top-most occupied cell
if (xsh->getColumn(index)->getSoundColumn()) {
color = m_soundColumnColor;
sideColor = m_soundColumnBorderColor;
} else {
TXshCell cell = xsh->getCell(r0, index); TXshCell cell = xsh->getCell(r0, index);
int ltype; int ltype;
getCellTypeAndColors(ltype, color, sideColor, cell); getCellTypeAndColors(ltype, color, sideColor, cell);
} }
}
if (xsh->getColumn(index)->isMask()) color = QColor(255, 0, 255); if (xsh->getColumn(index)->isMask()) color = QColor(255, 0, 255);
} }

View file

@ -677,7 +677,7 @@ void StageBuilder::addFrame(PlayerSet &players, ToonzScene *scene, TXsheet *xsh,
} }
TXshColumn *column = xsh->getColumn(c); TXshColumn *column = xsh->getColumn(c);
bool isMask = false; bool isMask = false;
if (column && !column->isEmpty()) { if (column && !column->isEmpty() && !column->getSoundColumn()) {
if (!column->isPreviewVisible() && checkPreviewVisibility) continue; if (!column->isPreviewVisible() && checkPreviewVisibility) continue;
if (column->isCamstandVisible() || if (column->isCamstandVisible() ||
includeUnvisible) // se l'"occhietto" non e' chiuso includeUnvisible) // se l'"occhietto" non e' chiuso

View file

@ -34,6 +34,7 @@
#include "orientation.h" #include "orientation.h"
#include "toonz/txsheet.h" #include "toonz/txsheet.h"
#include "toonz/preferences.h"
using namespace std; using namespace std;
@ -1488,7 +1489,20 @@ void TXsheet::scrub(int frame, bool isPreview) {
double samplePerFrame = st->getSampleRate() / fps; double samplePerFrame = st->getSampleRate() / fps;
double s0 = frame * samplePerFrame, s1 = s0 + samplePerFrame; double s0 = frame * samplePerFrame, s1 = s0 + samplePerFrame;
// if (m_player && m_player->isPlaying()) {
// try {
// m_player->stop();
// }
// catch (const std::runtime_error& e) {
// int i = 0;
// }
// catch (const std::exception& e) {
// int i = 0;
// }
// catch (...) {
// int i = 0;
// }
//}
play(st, s0, s1, false); play(st, s0, s1, false);
} catch (TSoundDeviceException &e) { } catch (TSoundDeviceException &e) {
if (e.getType() == TSoundDeviceException::NoDevice) { if (e.getType() == TSoundDeviceException::NoDevice) {

View file

@ -6,78 +6,16 @@
#include "toonz/toonzscene.h" #include "toonz/toonzscene.h"
#include "toonz/tproject.h" #include "toonz/tproject.h"
#include "toonz/sceneproperties.h" #include "toonz/sceneproperties.h"
#include "toonz/txshsoundlevel.h"
#include "tstream.h" #include "tstream.h"
#include "toutputproperties.h" #include "toutputproperties.h"
#include "tsop.h" #include "tsop.h"
#include "tconvert.h" #include "tconvert.h"
#include "toonz/preferences.h"
#include <QAudioFormat> #include <QAudioFormat>
#include <QAudioDeviceInfo> #include <QAudioDeviceInfo>
//=============================================================================
// ColumnLevel
//=============================================================================
class ColumnLevel {
TXshSoundLevelP m_soundLevel;
/*!Offsets: in frames. Start offset is a positive number.*/
int m_startOffset;
/*!Offsets: in frames. End offset is a positive number(to subtract to..).*/
int m_endOffset;
//! Starting frame in the timeline
int m_startFrame;
//! frameRate
double m_fps;
public:
ColumnLevel(TXshSoundLevel *soundLevel = 0, int startFrame = -1,
int startOffset = -1, int endOffset = -1, double fps = -1);
~ColumnLevel();
ColumnLevel *clone() const;
//! Overridden from TXshLevel
TXshSoundLevel *getSoundLevel() const { return m_soundLevel.getPointer(); }
void setSoundLevel(TXshSoundLevelP level) { m_soundLevel = level; }
void loadData(TIStream &is);
void saveData(TOStream &os);
void setStartOffset(int value);
int getStartOffset() const { return m_startOffset; }
void setEndOffset(int value);
int getEndOffset() const { return m_endOffset; }
void setOffsets(int startOffset, int endOffset);
//! Return the starting frame without offsets.
void setStartFrame(int frame) { m_startFrame = frame; }
int getStartFrame() const { return m_startFrame; }
//! Return the ending frame without offsets.
int getEndFrame() const;
//! Return frame count without offset.
int getFrameCount() const;
//! Return frame count with offset.
int getVisibleFrameCount() const;
//! Return start frame with offset.
int getVisibleStartFrame() const;
//! Return last frame with offset.
int getVisibleEndFrame() const;
//! Updates m_startOfset and m_endOffset.
void updateFrameRate(double newFrameRate);
void setFrameRate(double fps) { m_fps = fps; }
};
//============================================================================= //=============================================================================
ColumnLevel::ColumnLevel(TXshSoundLevel *soundLevel, int startFrame, ColumnLevel::ColumnLevel(TXshSoundLevel *soundLevel, int startFrame,
@ -381,18 +319,34 @@ const TXshCell &TXshSoundColumn::getCell(int row) const {
if (!l) return emptyCell; if (!l) return emptyCell;
TXshSoundLevel *soundLevel = l->getSoundLevel(); TXshSoundLevel *soundLevel = l->getSoundLevel();
TXshCell *cell = new TXshCell(soundLevel, TFrameId(row - l->getStartFrame())); TXshCell *cell = new TXshCell(soundLevel, TFrameId(row - l->getStartFrame()));
// La nuova cella aggiunge un reference al TXshSoundLevel; poiche' le celle // The new cell adds a reference to the TXshSoundLevel;
// delle // since the cells of the TXshSoundColumn are not persistent structures
// TXshSoundColumn non sono strutture persistenti ma sono strutture dinamiche // but are dynamic structures (they are recreated every time) I have to take
// (vengono ricreate ogni volta) devo occuparmi di fare il release altrimenti // care of making the release otherwise the TXshSoundLevel is never thrown
// il // away.
// TXshSoundLevel non viene mai buttato.
soundLevel->release(); soundLevel->release();
return *cell; return *cell;
} }
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
TXshCell TXshSoundColumn::getSoundCell(int row) {
static TXshCell emptyCell;
ColumnLevel* l = getColumnLevelByFrame(row);
if (row < 0 || row < getFirstRow() || row > getMaxFrame()) {
if (l) emptyCell.m_level = l->getSoundLevel();
return emptyCell;
}
if (!l) return emptyCell;
TXshSoundLevel* soundLevel = l->getSoundLevel();
TXshCell cell(soundLevel, TFrameId(row - l->getStartFrame()));
return cell;
}
//-----------------------------------------------------------------------------
bool TXshSoundColumn::isCellEmpty(int row) const { bool TXshSoundColumn::isCellEmpty(int row) const {
if (m_levels.empty()) return true; if (m_levels.empty()) return true;
ColumnLevel *l = getColumnLevelByFrame(row); ColumnLevel *l = getColumnLevelByFrame(row);
@ -978,7 +932,7 @@ TSoundTrackP TXshSoundColumn::getOverallSoundTrack(int fromFrame, int toFrame,
if (toFrame == -1) toFrame = getMaxFrame(); if (toFrame == -1) toFrame = getMaxFrame();
if (format.m_sampleRate == 0) { if (format.m_sampleRate == 0) {
// Found the best format inside the soundsequences // Find the best format inside the soundsequences
int sampleRate = 0; int sampleRate = 0;
int bitsPerSample = 8; int bitsPerSample = 8;
int channels = 1; int channels = 1;
@ -1015,10 +969,8 @@ TSoundTrackP TXshSoundColumn::getOverallSoundTrack(int fromFrame, int toFrame,
format.m_signedSample = true; format.m_signedSample = true;
} }
// We prefer to have 22050 as a maximum sampleRate (to avoid crashes or
// another issues)
#ifdef _WIN32 #ifdef _WIN32
if (format.m_sampleRate >= 44100) format.m_sampleRate = 22050; if (format.m_sampleRate > 44100) format.m_sampleRate = 44100;
#else #else
QAudioDeviceInfo info(QAudioDeviceInfo::defaultOutputDevice()); QAudioDeviceInfo info(QAudioDeviceInfo::defaultOutputDevice());
if (info.deviceName().length() == 0) throw TSoundDeviceException(TSoundDeviceException::NoDevice, if (info.deviceName().length() == 0) throw TSoundDeviceException(TSoundDeviceException::NoDevice,