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/txshcell.h"
#include "toonz/txshsoundlevel.h"
#include "tsound.h"
#include <QList>
@ -23,7 +24,69 @@
//=============================================================================
// forward declarations
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
@ -75,6 +138,7 @@ public:
int getFirstRow() const override;
const TXshCell &getCell(int row) const override;
TXshCell getSoundCell(int row);
void getCells(int row, int rowCount, TXshCell cells[]) override;
bool setCell(int row, const TXshCell &cell) override;

View file

@ -856,10 +856,12 @@ QString TTool::updateEnabled(int rowIndex, int columnIndex) {
// find the nearest level before it
if (levelType == NO_XSHLEVEL &&
!m_application->getCurrentFrame()->isEditingLevel()) {
TXshCell cell = xsh->getCell(rowIndex, columnIndex);
xl = cell.isEmpty() ? 0 : (TXshLevel *)(&cell.m_level);
sl = cell.isEmpty() ? 0 : cell.getSimpleLevel();
levelType = cell.isEmpty() ? NO_XSHLEVEL : cell.m_level->getType();
if (!column || (column && !column->getSoundColumn())) {
TXshCell cell = xsh->getCell(rowIndex, columnIndex);
xl = cell.isEmpty() ? 0 : (TXshLevel*)(&cell.m_level);
sl = cell.isEmpty() ? 0 : cell.getSimpleLevel();
levelType = cell.isEmpty() ? NO_XSHLEVEL : cell.m_level->getType();
}
}
if (Preferences::instance()->isAutoCreateEnabled()) {
@ -867,16 +869,18 @@ QString TTool::updateEnabled(int rowIndex, int columnIndex) {
// find the nearest level before it
if (levelType == NO_XSHLEVEL &&
!m_application->getCurrentFrame()->isEditingLevel()) {
int r0, r1;
xsh->getCellRange(columnIndex, r0, r1);
for (int r = std::min(r1, rowIndex); r > r0; r--) {
TXshCell cell = xsh->getCell(r, columnIndex);
if (cell.isEmpty()) continue;
xl = (TXshLevel *)(&cell.m_level);
sl = cell.getSimpleLevel();
levelType = cell.m_level->getType();
break;
}
if (!column || (column && !column->getSoundColumn())) {
int r0, r1;
xsh->getCellRange(columnIndex, r0, r1);
for (int r = std::min(r1, rowIndex); r > r0; r--) {
TXshCell cell = xsh->getCell(r, columnIndex);
if (cell.isEmpty()) continue;
xl = (TXshLevel*)(&cell.m_level);
sl = cell.getSimpleLevel();
levelType = cell.m_level->getType();
break;
}
}
}
// If the current tool does not match the current type, check for

View file

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

View file

@ -49,6 +49,7 @@
#include "toonz/tcamera.h"
#include "toonz/preferences.h"
#include "toonz/fullcolorpalette.h"
#include "toonz/txshsoundcolumn.h"
#include "toonzqt/tabbar.h"
@ -309,7 +310,9 @@ int TApp::getCurrentImageType() {
: TImage::RASTER; // and OVL_XSHLEVEL level types
}
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);
if (cell.isEmpty()) {
int r0, r1;
@ -357,7 +360,18 @@ void TApp::updateXshLevel() {
int column = m_currentColumn->getColumnIndex();
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);
xl = cell.m_level.getPointer();

View file

@ -645,7 +645,8 @@ void SceneViewerPanel::changeWindowTitle() {
return;
}
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 (!m_sceneViewer->is3DView()) {
TAffine aff = m_sceneViewer->getViewMatrix() *

View file

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

View file

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

View file

@ -128,9 +128,14 @@ void XsheetViewer::getColumnColor(QColor &color, QColor &sideColor, int index,
xsh->getCellRange(index, r0, r1);
if (0 <= r0 && r0 <= r1) {
// column color depends on the level type in the top-most occupied cell
TXshCell cell = xsh->getCell(r0, index);
int ltype;
getCellTypeAndColors(ltype, color, sideColor, cell);
if (xsh->getColumn(index)->getSoundColumn()) {
color = m_soundColumnColor;
sideColor = m_soundColumnBorderColor;
} else {
TXshCell cell = xsh->getCell(r0, index);
int ltype;
getCellTypeAndColors(ltype, color, sideColor, cell);
}
}
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);
bool isMask = false;
if (column && !column->isEmpty()) {
if (column && !column->isEmpty() && !column->getSoundColumn()) {
if (!column->isPreviewVisible() && checkPreviewVisibility) continue;
if (column->isCamstandVisible() ||
includeUnvisible) // se l'"occhietto" non e' chiuso

View file

@ -34,6 +34,7 @@
#include "orientation.h"
#include "toonz/txsheet.h"
#include "toonz/preferences.h"
using namespace std;
@ -781,7 +782,7 @@ void TXsheet::increaseStepCells(int r0, int c0, int &r1, int c1) {
// controllo se devo cambiare la selezione
bool allIncreaseIsEqual = true;
for (c = 0; c < ends.size() - 1 && allIncreaseIsEqual; c++)
allIncreaseIsEqual = allIncreaseIsEqual && ends[c] == ends[c + 1];
allIncreaseIsEqual = allIncreaseIsEqual && ends[c] == ends[c + 1];
if (allIncreaseIsEqual) r1 = ends[0];
}
@ -815,7 +816,7 @@ void TXsheet::decreaseStepCells(int r0, int c0, int &r1, int c1) {
// controllo se devo cambiare la selezione
bool allDecreaseIsEqual = true;
for (c = 0; c < ends.size() - 1 && allDecreaseIsEqual; c++)
allDecreaseIsEqual = allDecreaseIsEqual && ends[c] == ends[c + 1];
allDecreaseIsEqual = allDecreaseIsEqual && ends[c] == ends[c + 1];
if (allDecreaseIsEqual) r1 = ends[0];
}
@ -1477,7 +1478,7 @@ TSoundTrack *TXsheet::makeSound(SoundProperties *properties) {
void TXsheet::scrub(int frame, bool isPreview) {
try {
double fps =
getScene()->getProperties()->getOutputProperties()->getFrameRate();
getScene()->getProperties()->getOutputProperties()->getFrameRate();
TXsheet::SoundProperties *prop = new TXsheet::SoundProperties();
prop->m_isPreview = isPreview;
@ -1488,7 +1489,20 @@ void TXsheet::scrub(int frame, bool isPreview) {
double samplePerFrame = st->getSampleRate() / fps;
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);
} catch (TSoundDeviceException &e) {
if (e.getType() == TSoundDeviceException::NoDevice) {

View file

@ -6,78 +6,16 @@
#include "toonz/toonzscene.h"
#include "toonz/tproject.h"
#include "toonz/sceneproperties.h"
#include "toonz/txshsoundlevel.h"
#include "tstream.h"
#include "toutputproperties.h"
#include "tsop.h"
#include "tconvert.h"
#include "toonz/preferences.h"
#include <QAudioFormat>
#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,
@ -381,18 +319,34 @@ const TXshCell &TXshSoundColumn::getCell(int row) const {
if (!l) return emptyCell;
TXshSoundLevel *soundLevel = l->getSoundLevel();
TXshCell *cell = new TXshCell(soundLevel, TFrameId(row - l->getStartFrame()));
// La nuova cella aggiunge un reference al TXshSoundLevel; poiche' le celle
// delle
// TXshSoundColumn non sono strutture persistenti ma sono strutture dinamiche
// (vengono ricreate ogni volta) devo occuparmi di fare il release altrimenti
// il
// TXshSoundLevel non viene mai buttato.
// The new cell adds a reference to the TXshSoundLevel;
// since the cells of the TXshSoundColumn are not persistent structures
// but are dynamic structures (they are recreated every time) I have to take
// care of making the release otherwise the TXshSoundLevel is never thrown
// away.
soundLevel->release();
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 {
if (m_levels.empty()) return true;
ColumnLevel *l = getColumnLevelByFrame(row);
@ -978,7 +932,7 @@ TSoundTrackP TXshSoundColumn::getOverallSoundTrack(int fromFrame, int toFrame,
if (toFrame == -1) toFrame = getMaxFrame();
if (format.m_sampleRate == 0) {
// Found the best format inside the soundsequences
// Find the best format inside the soundsequences
int sampleRate = 0;
int bitsPerSample = 8;
int channels = 1;
@ -1015,10 +969,8 @@ TSoundTrackP TXshSoundColumn::getOverallSoundTrack(int fromFrame, int toFrame,
format.m_signedSample = true;
}
// We prefer to have 22050 as a maximum sampleRate (to avoid crashes or
// another issues)
#ifdef _WIN32
if (format.m_sampleRate >= 44100) format.m_sampleRate = 22050;
if (format.m_sampleRate > 44100) format.m_sampleRate = 44100;
#else
QAudioDeviceInfo info(QAudioDeviceInfo::defaultOutputDevice());
if (info.deviceName().length() == 0) throw TSoundDeviceException(TSoundDeviceException::NoDevice,