| |
| |
| #include "toonz/txshsoundcolumn.h" |
| #include "toonz/levelset.h" |
| #include "toonz/txsheet.h" |
| #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" |
| |
| |
| |
| |
| |
| class ColumnLevel |
| { |
| TXshSoundLevelP m_soundLevel; |
| |
| |
| int m_startOffset; |
| |
| int m_endOffset; |
| |
| |
| int m_startFrame; |
| |
| |
| double m_fps; |
| |
| public: |
| ColumnLevel(TXshSoundLevel *soundLevel = 0, int startFrame = -1, int startOffset = -1, int endOffset = -1, double fps = -1); |
| ~ColumnLevel(); |
| ColumnLevel *clone() const; |
| |
| |
| 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); |
| |
| |
| void setStartFrame(int frame) { m_startFrame = frame; } |
| int getStartFrame() const { return m_startFrame; } |
| |
| |
| int getEndFrame() const; |
| |
| |
| int getFrameCount() const; |
| |
| |
| int getVisibleFrameCount() const; |
| |
| |
| int getVisibleStartFrame() const; |
| |
| int getVisibleEndFrame() const; |
| |
| void updateFrameRate(double newFrameRate); |
| |
| void setFrameRate(double fps) { m_fps = fps; } |
| }; |
| |
| |
| |
| ColumnLevel::ColumnLevel(TXshSoundLevel *soundLevel, int startFrame, int startOffset, int endOffset, double fps) |
| : m_soundLevel(soundLevel), m_startOffset(startOffset), m_endOffset(endOffset), m_startFrame(startFrame), m_fps(fps) |
| { |
| } |
| |
| |
| |
| ColumnLevel::~ColumnLevel() |
| { |
| } |
| |
| |
| |
| ColumnLevel *ColumnLevel::clone() const |
| { |
| ColumnLevel *soundColumnLevel = new ColumnLevel(); |
| soundColumnLevel->setSoundLevel(getSoundLevel()); |
| soundColumnLevel->setStartFrame(m_startFrame); |
| soundColumnLevel->setStartOffset(m_startOffset); |
| soundColumnLevel->setEndOffset(m_endOffset); |
| soundColumnLevel->setFrameRate(m_fps); |
| return soundColumnLevel; |
| } |
| |
| |
| |
| void ColumnLevel::loadData(TIStream &is) |
| { |
| string tagName; |
| is.openChild(tagName); |
| if (tagName == "SoundCells") { |
| TPersist *p = 0; |
| is >> m_startOffset >> m_endOffset >> m_startFrame >> p; |
| TXshSoundLevel *xshLevel = dynamic_cast<TXshSoundLevel *>(p); |
| if (xshLevel) |
| m_soundLevel = xshLevel; |
| } |
| is.closeChild(); |
| } |
| |
| |
| |
| void ColumnLevel::saveData(TOStream &os) |
| { |
| os.child("SoundCells") << getStartOffset() << getEndOffset() << getStartFrame() << m_soundLevel.getPointer(); |
| } |
| |
| |
| |
| void ColumnLevel::setStartOffset(int value) |
| { |
| if (!m_soundLevel) |
| return; |
| if (value < 0 || value > getFrameCount() - getEndOffset() - 1) |
| return; |
| m_startOffset = value; |
| } |
| |
| |
| |
| void ColumnLevel::setEndOffset(int value) |
| { |
| if (!m_soundLevel) |
| return; |
| if (value < 0 || getStartFrame() + getFrameCount() - value < getStartFrame() + getStartOffset() + 1) |
| return; |
| m_endOffset = value; |
| } |
| |
| |
| |
| void ColumnLevel::setOffsets(int startOffset, int endOffset) |
| { |
| assert(startOffset > 0 && endOffset > 0); |
| |
| if (startOffset < 0 || startOffset > getFrameCount() - endOffset - 1) |
| return; |
| m_startOffset = startOffset; |
| if (endOffset < 0 || getStartFrame() + getFrameCount() - endOffset < getStartFrame() + getStartOffset() + 1) |
| return; |
| m_endOffset = endOffset; |
| } |
| |
| |
| |
| int ColumnLevel::getEndFrame() const |
| { |
| if (!m_soundLevel) |
| return -1; |
| return getStartFrame() + getFrameCount() - 1; |
| } |
| |
| |
| |
| int ColumnLevel::getFrameCount() const |
| { |
| if (!m_soundLevel) |
| return -1; |
| return m_soundLevel->getFrameCount(); |
| } |
| |
| |
| |
| int ColumnLevel::getVisibleFrameCount() const |
| { |
| if (!m_soundLevel) |
| return -1; |
| return getFrameCount() - getStartOffset() - getEndOffset(); |
| } |
| |
| |
| |
| int ColumnLevel::getVisibleStartFrame() const |
| { |
| if (!m_soundLevel) |
| return -1; |
| return getStartFrame() + getStartOffset(); |
| } |
| |
| |
| |
| int ColumnLevel::getVisibleEndFrame() const |
| { |
| if (!m_soundLevel) |
| return -1; |
| return getVisibleStartFrame() + getVisibleFrameCount() - 1; |
| } |
| |
| |
| |
| void ColumnLevel::updateFrameRate(double newFrameRate) |
| { |
| if (m_fps == newFrameRate) |
| return; |
| double fact = (double)newFrameRate / m_fps; |
| m_startFrame = tround(m_startFrame * fact); |
| m_startOffset = tround(m_startOffset * fact); |
| m_endOffset = tround(m_endOffset * fact); |
| m_fps = newFrameRate; |
| } |
| |
| |
| namespace |
| { |
| |
| |
| bool lessThan(const ColumnLevel *s1, const ColumnLevel *s2) |
| { |
| return s1->getVisibleStartFrame() < s2->getVisibleStartFrame(); |
| } |
| |
| |
| } |
| |
| |
| TXshSoundColumn::TXshSoundColumn() |
| : m_player(0), m_volume(0.4), m_currentPlaySoundTrack(0), m_isOldVersion(false) |
| { |
| m_timer.setInterval(500); |
| m_timer.setSingleShot(true); |
| m_timer.stop(); |
| |
| connect(&m_timer, SIGNAL(timeout()), this, SLOT(onTimerOut())); |
| } |
| |
| |
| |
| TXshSoundColumn::~TXshSoundColumn() |
| { |
| clear(); |
| if (m_timer.isActive()) { |
| m_timer.stop(); |
| stop(); |
| } |
| } |
| |
| |
| |
| TXshColumn::ColumnType TXshSoundColumn::getColumnType() const |
| { |
| return eSoundType; |
| } |
| |
| |
| |
| bool TXshSoundColumn::canSetCell(const TXshCell &cell) const |
| { |
| return cell.isEmpty() || cell.m_level->getSoundLevel() != 0; |
| } |
| |
| |
| |
| TXshColumn *TXshSoundColumn::clone() const |
| { |
| TXshSoundColumn *column = new TXshSoundColumn(); |
| column->setVolume(m_volume); |
| column->setXsheet(getXsheet()); |
| int i; |
| for (i = 0; i < m_levels.size(); i++) |
| column->insertColumnLevel(m_levels.at(i)->clone(), i); |
| |
| return column; |
| } |
| |
| |
| |
| void TXshSoundColumn::assignLevels(const TXshSoundColumn *src) |
| { |
| |
| clear(); |
| |
| int r; |
| for (r = src->getFirstRow(); r <= src->getMaxFrame(); r++) { |
| int r0, r1; |
| if (!src->getLevelRange(r, r0, r1)) |
| continue; |
| TXshCell cell = src->getCell(r); |
| if (cell.isEmpty()) |
| continue; |
| TXshSoundLevel *soundLevel = cell.m_level->getSoundLevel(); |
| assert(!!soundLevel); |
| int startOffset = cell.getFrameId().getNumber(); |
| int startFrame = r - startOffset; |
| int endOffset = startFrame + soundLevel->getFrameCount() - r1 - 1; |
| ColumnLevel *l = new ColumnLevel(soundLevel, startFrame, startOffset, endOffset); |
| insertColumnLevel(l); |
| r = r1; |
| } |
| } |
| |
| |
| |
| void TXshSoundColumn::loadData(TIStream &is) |
| { |
| VersionNumber tnzVersion = is.getVersion(); |
| if (tnzVersion < VersionNumber(1, 17)) { |
| TFilePath path; |
| is >> path; |
| m_isOldVersion = true; |
| int offset = 0; |
| is >> offset; |
| is >> m_volume; |
| if (!is.eos()) { |
| int status; |
| is >> status; |
| setStatusWord(status); |
| } |
| TXshSoundLevelP level = new TXshSoundLevel(path.getWideName()); |
| level->setPath(path); |
| ColumnLevel *l = new ColumnLevel(level.getPointer(), offset, 0, 0); |
| insertColumnLevel(l); |
| return; |
| } |
| is >> m_volume; |
| int levelCount = 0; |
| is >> levelCount; |
| |
| int i; |
| for (i = 0; i < levelCount; i++) { |
| ColumnLevel *sl = new ColumnLevel(); |
| sl->loadData(is); |
| insertColumnLevel(sl, i); |
| } |
| if (!is.eos()) { |
| int status; |
| is >> status; |
| setStatusWord(status); |
| } |
| } |
| |
| |
| |
| void TXshSoundColumn::saveData(TOStream &os) |
| { |
| os << m_volume; |
| int levelsCount = m_levels.size(); |
| os << levelsCount; |
| if (levelsCount == 0) |
| return; |
| int i; |
| for (i = 0; i < levelsCount; i++) |
| m_levels.at(i)->saveData(os); |
| os << getStatusWord(); |
| } |
| |
| |
| |
| int TXshSoundColumn::getRange(int &r0, int &r1) const |
| { |
| r0 = getFirstRow(); |
| r1 = getMaxFrame(); |
| return r1 - r0 + 1; |
| } |
| |
| |
| |
| int TXshSoundColumn::getRowCount() const |
| { |
| return getMaxFrame() - getFirstRow(); |
| } |
| |
| |
| |
| int TXshSoundColumn::getMaxFrame() const |
| { |
| int levelsCount = m_levels.size(); |
| if (levelsCount == 0) |
| return -1; |
| return m_levels.at(levelsCount - 1)->getVisibleEndFrame(); |
| } |
| |
| |
| |
| int TXshSoundColumn::getFirstRow() const |
| { |
| if (m_levels.size() == 0) |
| return -1; |
| return m_levels.at(0)->getVisibleStartFrame(); |
| } |
| |
| |
| |
| const TXshCell &TXshSoundColumn::getCell(int row) const |
| { |
| 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 = new TXshCell(soundLevel, TFrameId(row - l->getStartFrame())); |
| |
| |
| |
| |
| soundLevel->release(); |
| return *cell; |
| } |
| |
| |
| |
| bool TXshSoundColumn::isCellEmpty(int row) const |
| { |
| if (m_levels.empty()) |
| return true; |
| ColumnLevel *l = getColumnLevelByFrame(row); |
| if (!l || !l->getSoundLevel()) |
| return true; |
| return false; |
| } |
| |
| |
| |
| void TXshSoundColumn::checkColumn() const |
| { |
| #ifndef NDEBUG |
| int size = m_levels.size(); |
| int i; |
| for (i = 0; i < size; i++) { |
| ColumnLevel *level = m_levels.at(i); |
| assert(level); |
| assert(level->getSoundLevel()); |
| int start1 = level->getVisibleStartFrame(); |
| int end1 = level->getVisibleEndFrame(); |
| assert(start1 <= end1); |
| if (i < size - 1) { |
| ColumnLevel *nextLevel = m_levels.at(i + 1); |
| assert(nextLevel); |
| assert(nextLevel->getSoundLevel()); |
| int start2 = nextLevel->getVisibleStartFrame(); |
| int end2 = nextLevel->getVisibleEndFrame(); |
| assert(start2 <= end2); |
| assert(end1 < start2); |
| } |
| } |
| #endif |
| } |
| |
| |
| |
| void TXshSoundColumn::getCells(int row, int rowCount, TXshCell cells[]) |
| { |
| |
| int ra = row; |
| int rb = row + rowCount - 1; |
| assert(ra <= rb); |
| TXshCell *dstCell = cells; |
| int r; |
| for (r = ra; r <= rb; r++) |
| *cells++ = getCell(r); |
| checkColumn(); |
| } |
| |
| |
| |
| void TXshSoundColumn::setCellInEmptyFrame(int row, const TXshCell &cell) |
| { |
| if (cell.isEmpty()) |
| return; |
| TXshSoundLevel *soundLevel = cell.getSoundLevel(); |
| if (!soundLevel) |
| return; |
| int startOffset = cell.getFrameId().getNumber(); |
| int startFrame = row - startOffset; |
| int endOffset = startFrame + soundLevel->getFrameCount() - 1 - row; |
| insertColumnLevel(new ColumnLevel(soundLevel, startFrame, startOffset, endOffset)); |
| } |
| |
| |
| |
| bool TXshSoundColumn::setCell(int row, const TXshCell &cell) |
| { |
| return setCell(row, cell, false); |
| } |
| |
| |
| |
| bool TXshSoundColumn::setCell(int row, const TXshCell &cell, bool updateSequence) |
| { |
| if (!canSetCell(cell)) |
| return false; |
| assert(row >= 0); |
| ColumnLevel *lBefore = getColumnLevelByFrame(row - 1); |
| ColumnLevel *l = getColumnLevelByFrame(row); |
| ColumnLevel *lNext = getColumnLevelByFrame(row + 1); |
| |
| |
| if (!updateSequence && |
| l && l->getSoundLevel() == cell.getSoundLevel() && |
| row - l->getStartFrame() == cell.getFrameId().getNumber()) |
| return false; |
| |
| bool isBeforeLevelInSequence = (lBefore && |
| lBefore->getSoundLevel() == cell.getSoundLevel() && |
| row - lBefore->getStartFrame() == cell.getFrameId().getNumber()); |
| |
| bool isNextLevelInSequence = (lNext && |
| lNext->getSoundLevel() == cell.getSoundLevel() && |
| row - lNext->getStartFrame() == cell.getFrameId().getNumber()); |
| |
| |
| if (isBeforeLevelInSequence) { |
| int oldEndOffset = lBefore->getEndOffset(); |
| int endOffset = (lBefore->getVisibleEndFrame() != row) ? oldEndOffset - 1 : oldEndOffset; |
| if (isNextLevelInSequence) { |
| endOffset = lNext->getEndOffset(); |
| |
| if (lNext != lBefore) |
| removeColumnLevel(lNext); |
| } |
| if (l && l != lBefore) { |
| if (l->getVisibleFrameCount() == 1) |
| removeColumnLevel(l); |
| else |
| l->setStartOffset(l->getStartOffset() + 1); |
| } |
| lBefore->setEndOffset(endOffset); |
| checkColumn(); |
| return true; |
| } |
| |
| if (isNextLevelInSequence) { |
| int oldStartOffset = lNext->getStartOffset(); |
| int startOffset = (lNext->getVisibleStartFrame() != row) ? oldStartOffset - 1 : oldStartOffset; |
| if (l && l != lNext) { |
| if (l->getVisibleFrameCount() == 1) |
| removeColumnLevel(l); |
| else |
| l->setEndOffset(l->getEndOffset() + 1); |
| } |
| lNext->setStartOffset(startOffset); |
| checkColumn(); |
| return true; |
| } |
| |
| |
| clearCells(row, 1); |
| setCellInEmptyFrame(row, cell); |
| checkColumn(); |
| return true; |
| } |
| |
| |
| |
| bool TXshSoundColumn::setCells(int row, int rowCount, const TXshCell cells[]) |
| { |
| assert(row >= 0); |
| |
| int ra = row; |
| int rb = row + rowCount - 1; |
| assert(ra <= rb); |
| bool ret = false; |
| int r; |
| for (r = ra; r <= rb; r++) { |
| bool isOneCellSet = setCell(r, cells[r - ra]); |
| if (isOneCellSet) |
| ret = isOneCellSet; |
| } |
| return ret; |
| } |
| |
| |
| |
| void TXshSoundColumn::insertEmptyCells(int row, int rowCount) |
| { |
| if (m_levels.isEmpty()) |
| return; |
| |
| int ra = row; |
| int rb = row + rowCount - 1; |
| assert(ra <= rb); |
| |
| |
| ColumnLevel *l = getColumnLevelByFrame(ra); |
| if (l && l->getVisibleStartFrame() < ra) { |
| int oldOffset = l->getEndOffset(); |
| l->setEndOffset(oldOffset + l->getVisibleEndFrame() - ra + 1); |
| insertColumnLevel(new ColumnLevel(l->getSoundLevel(), l->getStartFrame(), row - l->getStartFrame(), oldOffset)); |
| } |
| |
| |
| int i; |
| for (i = m_levels.count() - 1; i >= 0; i--) { |
| ColumnLevel *cl = m_levels.at(i); |
| if (cl->getVisibleStartFrame() < ra) |
| continue; |
| cl->setStartFrame(cl->getStartFrame() + rowCount); |
| } |
| checkColumn(); |
| } |
| |
| |
| |
| void TXshSoundColumn::removeCells(int row, int rowCount, bool shift) |
| { |
| |
| int ra = row; |
| int rb = row + rowCount - 1; |
| assert(ra <= rb); |
| |
| int i; |
| for (i = m_levels.size() - 1; i >= 0; i--) { |
| ColumnLevel *l = m_levels.at(i); |
| if (!l) |
| continue; |
| int visibleStartFrame = l->getVisibleStartFrame(); |
| int visibleEndFrame = l->getVisibleEndFrame(); |
| |
| if (visibleStartFrame > rb || visibleEndFrame < ra) |
| continue; |
| int newEndOffset = l->getEndFrame() - ra + 1; |
| int newStartOffset = rb - l->getStartFrame() + 1; |
| |
| if (visibleStartFrame < ra && visibleEndFrame > rb) { |
| int oldEndOffset = l->getEndOffset(); |
| l->setEndOffset(newEndOffset); |
| insertColumnLevel(new ColumnLevel(l->getSoundLevel(), l->getStartFrame(), newStartOffset, oldEndOffset)); |
| continue; |
| } |
| if (visibleStartFrame < ra) |
| l->setEndOffset(newEndOffset); |
| if (visibleEndFrame > rb) |
| l->setStartOffset(newStartOffset); |
| |
| if (visibleStartFrame >= ra && visibleEndFrame <= rb) |
| removeColumnLevel(l); |
| } |
| |
| if (shift) { |
| for (i = m_levels.size() - 1; i >= 0; i--) { |
| ColumnLevel *l = m_levels.at(i); |
| if (!l) |
| continue; |
| int visibleStartFrame = l->getVisibleStartFrame(); |
| int visibleEndFrame = l->getVisibleEndFrame(); |
| if (visibleStartFrame > ra) |
| l->setStartFrame(l->getStartFrame() - rowCount); |
| } |
| |
| |
| ColumnLevel *beforeL = getColumnLevelByFrame(ra - 1); |
| ColumnLevel *nextL = getColumnLevelByFrame(ra); |
| if (beforeL && nextL && |
| beforeL->getSoundLevel() == nextL->getSoundLevel() && |
| beforeL->getStartFrame() == nextL->getStartFrame()) { |
| beforeL->setEndOffset(nextL->getEndOffset()); |
| removeColumnLevel(nextL); |
| } |
| } |
| |
| checkColumn(); |
| } |
| |
| |
| |
| void TXshSoundColumn::clearCells(int row, int rowCount) |
| { |
| if (rowCount <= 0) |
| return; |
| if (m_levels.isEmpty()) |
| return; |
| removeCells(row, rowCount, false); |
| } |
| |
| |
| |
| void TXshSoundColumn::removeCells(int row, int rowCount) |
| { |
| removeCells(row, rowCount, true); |
| } |
| |
| |
| |
| void TXshSoundColumn::updateCells(int row, int rowCount) |
| { |
| int r; |
| for (r = row; r < row + rowCount; r++) { |
| TXshCell cell = getCell(r); |
| setCell(row, cell, true); |
| } |
| } |
| |
| |
| |
| int TXshSoundColumn::modifyCellRange(int row, int delta, bool modifyStartValue) |
| { |
| ColumnLevel *l = getColumnLevelByFrame(row); |
| if (!l) |
| return -1; |
| |
| int startVisibleFrame = l->getVisibleStartFrame(); |
| int endVisibleFrame = l->getVisibleEndFrame(); |
| |
| if (startVisibleFrame != row && endVisibleFrame != row) |
| return -1; |
| |
| int r0 = delta > 0 ? row : row + delta; |
| int r1 = delta > 0 ? row + delta : row; |
| |
| int r; |
| for (r = r0; r <= r1; r++) { |
| ColumnLevel *oldL = getColumnLevelByFrame(r); |
| if (!oldL || oldL == l) |
| continue; |
| int visibleStartFrame = oldL->getVisibleStartFrame(); |
| int visibleEndFrame = oldL->getVisibleEndFrame(); |
| if (visibleStartFrame >= r0 && visibleEndFrame <= r1) |
| removeColumnLevel(oldL); |
| if (visibleStartFrame <= r0) |
| oldL->setEndOffset(oldL->getEndOffset() + visibleEndFrame - r0 + 1); |
| if (visibleEndFrame >= r1) |
| oldL->setStartOffset(oldL->getStartOffset() + r1 - visibleStartFrame + 1); |
| r = visibleEndFrame; |
| } |
| |
| if (modifyStartValue) { |
| |
| if (endVisibleFrame < startVisibleFrame + delta) |
| delta = endVisibleFrame - startVisibleFrame; |
| int newStartOffset = l->getStartOffset() + delta; |
| |
| if (newStartOffset < 0) |
| newStartOffset = 0; |
| l->setStartOffset(newStartOffset); |
| checkColumn(); |
| getXsheet()->updateFrameCount(); |
| return l->getVisibleStartFrame(); |
| } |
| |
| |
| if (startVisibleFrame > endVisibleFrame + delta) |
| delta = startVisibleFrame - endVisibleFrame; |
| |
| int newEndOffset = l->getEndOffset() - delta; |
| if (newEndOffset < 0) |
| newEndOffset = 0; |
| l->setEndOffset(newEndOffset); |
| checkColumn(); |
| getXsheet()->updateFrameCount(); |
| return l->getVisibleEndFrame(); |
| } |
| |
| |
| |
| bool TXshSoundColumn::getLevelRange(int row, int &r0, int &r1) const |
| { |
| ColumnLevel *l = getColumnLevelByFrame(row); |
| if (!l) { |
| r0 = r1 = row; |
| return false; |
| } |
| r0 = l->getVisibleStartFrame(); |
| r1 = l->getVisibleEndFrame(); |
| return true; |
| } |
| |
| |
| |
| bool TXshSoundColumn::getLevelRangeWithoutOffset(int row, int &r0, int &r1) const |
| { |
| ColumnLevel *l = getColumnLevelByFrame(row); |
| if (!l) { |
| r0 = r1 = row; |
| return false; |
| } |
| r0 = l->getStartFrame(); |
| r1 = l->getEndFrame(); |
| return true; |
| } |
| |
| |
| |
| void TXshSoundColumn::setXsheet(TXsheet *xsheet) |
| { |
| TXshColumn::setXsheet(xsheet); |
| ToonzScene *scene = xsheet->getScene(); |
| if (!scene || m_levels.empty()) |
| return; |
| |
| if (m_isOldVersion) { |
| assert(m_levels.size() == 1); |
| scene->getLevelSet()->insertLevel(m_levels.at(0)->getSoundLevel()); |
| m_isOldVersion = false; |
| } |
| |
| TOutputProperties *properties = scene->getProperties()->getOutputProperties(); |
| setFrameRate(properties->getFrameRate()); |
| } |
| |
| |
| |
| void TXshSoundColumn::setFrameRate(double fps) |
| { |
| if (m_levels.empty()) |
| return; |
| int i; |
| for (i = 0; i < m_levels.size(); i++) { |
| ColumnLevel *column = m_levels.at(i); |
| TXshSoundLevel *soundLevel = column->getSoundLevel(); |
| if (soundLevel->getFrameRate() != fps) |
| soundLevel->setFrameRate(fps); |
| column->setFrameRate(fps); |
| } |
| } |
| |
| |
| |
| void TXshSoundColumn::updateFrameRate(double fps) |
| { |
| if (m_levels.empty()) |
| return; |
| int i; |
| for (i = 0; i < m_levels.size(); i++) { |
| ColumnLevel *column = m_levels.at(i); |
| TXshSoundLevel *soundLevel = column->getSoundLevel(); |
| double oldFps = soundLevel->getFrameRate(); |
| if (oldFps != fps) |
| soundLevel->setFrameRate(fps); |
| column->updateFrameRate(fps); |
| } |
| } |
| |
| |
| |
| void TXshSoundColumn::setVolume(double value) |
| { |
| m_volume = tcrop<double>(value, 0.0, 1.0); |
| if (m_player && m_player->isPlaying()) |
| #ifdef MACOSX |
| m_player->setVolume(m_volume); |
| #else |
| stop(); |
| #endif |
| } |
| |
| |
| |
| double TXshSoundColumn::getVolume() const |
| { |
| return m_volume; |
| } |
| |
| |
| |
| void TXshSoundColumn::play(TSoundTrackP soundtrack, int s0, int s1, bool loop) |
| { |
| if (!TSoundOutputDevice::installed()) |
| return; |
| |
| if (!m_player) |
| m_player = new TSoundOutputDevice(); |
| |
| if (m_player) { |
| try { |
| #ifdef MACOSX |
| m_player->setVolume(m_volume); |
| TSoundTrackP mixedTrack = soundtrack; |
| #else |
| TSoundTrackP mixedTrack = TSoundTrack::create(soundtrack->getFormat(), soundtrack->getSampleCount()); |
| mixedTrack = TSop::mix(mixedTrack, soundtrack, 1.0, m_volume); |
| #endif |
| m_player->play(mixedTrack, s0, s1, loop); |
| m_currentPlaySoundTrack = mixedTrack; |
| #ifndef MACOSX |
| m_timer.start(); |
| #endif |
| } catch (TSoundDeviceException &) { |
| } |
| } |
| } |
| |
| |
| |
| void TXshSoundColumn::play(ColumnLevel *columnLevel, int currentFrame) |
| { |
| assert(columnLevel); |
| TXshSoundLevel *soundLevel = columnLevel->getSoundLevel(); |
| int offset = 0; |
| int startFrame = currentFrame - columnLevel->getStartFrame(); |
| int endFrame = soundLevel->getFrameCount() - columnLevel->getEndOffset(); |
| int spf = soundLevel->getSamplePerFrame(); |
| int s0 = startFrame * spf; |
| int s1 = endFrame * spf; |
| |
| if (!soundLevel->getSoundTrack()) |
| return; |
| play(soundLevel->getSoundTrack(), s0, s1, false); |
| } |
| |
| |
| |
| void TXshSoundColumn::play(int currentFrame) |
| { |
| TSoundTrackP soundTrack = getOverallSoundTrack(currentFrame); |
| |
| if (!soundTrack) |
| return; |
| |
| int spf = m_levels.at(0)->getSoundLevel()->getSamplePerFrame(); |
| int startFrame = (currentFrame - getFirstRow()); |
| |
| int s0 = startFrame * spf; |
| int s1 = getMaxFrame() * spf; |
| |
| play(soundTrack, s0, s1, false); |
| } |
| |
| |
| |
| void TXshSoundColumn::stop() |
| { |
| if (m_player) { |
| m_player->stop(); |
| m_player->close(); |
| m_player = 0; |
| m_currentPlaySoundTrack = TSoundTrackP(); |
| } |
| } |
| |
| |
| |
| bool TXshSoundColumn::isPlaying() const |
| { |
| return m_player && m_player->isPlaying(); |
| } |
| |
| |
| |
| void TXshSoundColumn::insertColumnLevel(ColumnLevel *columnLevel, int index) |
| { |
| if (index == -1) |
| index = m_levels.size(); |
| m_levels.insert(index, columnLevel); |
| qSort(m_levels.begin(), m_levels.end(), lessThan); |
| } |
| |
| |
| |
| void TXshSoundColumn::removeColumnLevel(ColumnLevel *columnLevel) |
| { |
| if (!columnLevel) |
| return; |
| int index = m_levels.indexOf(columnLevel); |
| if (index == -1) |
| return; |
| m_levels.removeAt(index); |
| delete columnLevel; |
| } |
| |
| |
| |
| ColumnLevel *TXshSoundColumn::getColumnLevelByFrame(int frame) const |
| { |
| int levelCount = m_levels.size(); |
| for (int i = 0; i < levelCount; i++) { |
| ColumnLevel *l = m_levels.at(i); |
| TXshSoundLevel *soundLevel = l->getSoundLevel(); |
| int startFrame = l->getStartFrame() + l->getStartOffset(); |
| int frameCount = soundLevel->getFrameCount() - l->getStartOffset() - l->getEndOffset(); |
| if (startFrame <= frame && startFrame + frameCount > frame) |
| return l; |
| } |
| return 0; |
| } |
| |
| |
| |
| ColumnLevel *TXshSoundColumn::getColumnLevel(int index) |
| { |
| if (index < 0 || index >= m_levels.count()) |
| return 0; |
| return m_levels.at(index); |
| } |
| |
| |
| |
| int TXshSoundColumn::getColumnLevelIndex(ColumnLevel *columnLevel) const |
| { |
| return m_levels.indexOf(columnLevel); |
| } |
| |
| |
| |
| void TXshSoundColumn::clear() |
| { |
| int sequenceCount = m_levels.size(); |
| for (int i = 0; i < sequenceCount; i++) { |
| ColumnLevel *s = m_levels[i]; |
| delete s; |
| } |
| m_levels.clear(); |
| } |
| |
| |
| void TXshSoundColumn::onTimerOut() |
| { |
| #ifndef MACOSX |
| if (m_player && m_player->isAllQueuedItemsPlayed()) |
| stop(); |
| #endif |
| } |
| |
| |
| |
| void TXshSoundColumn::scrub(int fromFrame, int toFrame) |
| { |
| if (!isCamstandVisible()) |
| return; |
| TSoundTrackP soundTrack = getOverallSoundTrack(fromFrame, toFrame + 1); |
| if (!soundTrack) |
| return; |
| |
| play(soundTrack, 0, soundTrack->getSampleCount(), false); |
| } |
| |
| |
| |
| TSoundTrackP TXshSoundColumn::getOverallSoundTrack(int fromFrame, int toFrame, double fps, TSoundTrackFormat format) |
| { |
| int levelsCount = m_levels.size(); |
| |
| if (levelsCount == 0) |
| return 0; |
| |
| if (fps == -1) |
| fps = m_levels[0]->getSoundLevel()->getFrameRate(); |
| if (fromFrame == -1) |
| fromFrame = getFirstRow(); |
| if (toFrame == -1) |
| toFrame = getMaxFrame(); |
| |
| if (format.m_sampleRate == 0) { |
| |
| int sampleRate = 0; |
| int bitsPerSample = 8; |
| int channels = 1; |
| for (int i = 0; i < levelsCount; i++) { |
| TXshSoundLevel *soundLevel = m_levels.at(i)->getSoundLevel(); |
| TSoundTrackP soundTrack = soundLevel->getSoundTrack(); |
| if (soundTrack.getPointer() == 0) |
| continue; |
| TSoundTrackFormat f = soundTrack->getFormat(); |
| if ((int)f.m_sampleRate > sampleRate) { |
| format.m_sampleRate = f.m_sampleRate; |
| sampleRate = f.m_sampleRate; |
| format.m_channelCount = f.m_channelCount; |
| channels = f.m_channelCount; |
| format.m_signedSample = f.m_signedSample; |
| format.m_bitPerSample = f.m_bitPerSample; |
| bitsPerSample = f.m_bitPerSample; |
| } |
| if (f.m_channelCount > channels) { |
| format.m_channelCount = f.m_channelCount; |
| channels = f.m_channelCount; |
| } |
| if (f.m_bitPerSample > bitsPerSample) { |
| format.m_bitPerSample = f.m_bitPerSample; |
| bitsPerSample = f.m_bitPerSample; |
| } |
| } |
| } |
| |
| |
| if (levelsCount == 0 || format.m_sampleRate == 0) { |
| format.m_sampleRate = 44100; |
| format.m_bitPerSample = 16; |
| format.m_channelCount = 1; |
| format.m_signedSample = true; |
| } |
| |
| |
| if (format.m_sampleRate >= 44100) |
| format.m_sampleRate = 22050; |
| |
| |
| double samplePerFrame = format.m_sampleRate / fps; |
| |
| |
| double duration = double(toFrame - fromFrame) / fps; |
| |
| |
| double dsamp = duration * format.m_sampleRate; |
| TINT32 lsamp = (TINT32)dsamp; |
| if ((double)lsamp < dsamp - TConsts::epsilon) |
| lsamp++; |
| |
| TSoundTrackP overallSoundTrack; |
| |
| try { |
| overallSoundTrack = TSoundTrack::create(format, lsamp); |
| } catch (TSoundDeviceException &) { |
| } |
| |
| |
| overallSoundTrack->blank(0, lsamp); |
| |
| if (levelsCount == 0) |
| return overallSoundTrack; |
| |
| for (int i = 0; i < levelsCount; i++) { |
| ColumnLevel *l = m_levels.at(i); |
| TXshSoundLevel *soundLevel = l->getSoundLevel(); |
| |
| |
| int levelStartFrame = l->getStartFrame() + l->getStartOffset(); |
| int levelEndFrame = levelStartFrame + soundLevel->getFrameCount() - l->getStartOffset() - l->getEndOffset(); |
| |
| if ((levelStartFrame < fromFrame && levelEndFrame < fromFrame)) |
| continue; |
| |
| if ((levelStartFrame > toFrame && levelEndFrame > toFrame)) |
| break; |
| |
| |
| |
| TSoundTrackP s = soundLevel->getSoundTrack(); |
| if (!s) |
| continue; |
| TSoundTrackP soundTrack = TSop::convert(s, format); |
| |
| int s0delta = 0; |
| if (fromFrame > levelStartFrame) |
| s0delta = fromFrame - levelStartFrame; |
| |
| int s0 = (l->getStartOffset() + s0delta) * samplePerFrame; |
| |
| int s1delta = 0; |
| if (toFrame < levelEndFrame) |
| s1delta = levelEndFrame - toFrame; |
| int s1 = (soundLevel->getFrameCount() - l->getEndOffset() - s1delta) * samplePerFrame; |
| |
| if (s1 > 0 && s1 >= s0) { |
| soundTrack = soundTrack->extract(s0, s1); |
| |
| |
| overallSoundTrack->copy(soundTrack, |
| int((levelStartFrame - fromFrame) * samplePerFrame)); |
| } |
| } |
| |
| return overallSoundTrack; |
| } |
| |
| |
| |
| TSoundTrackP TXshSoundColumn::mixingTogether(const std::vector<TXshSoundColumn *> &vect, int fromFrame, int toFrame, double fps) |
| { |
| int offset = 0xffff; |
| long sampleCount = 0; |
| std::vector<TSoundTrackP> tracks; |
| TSoundTrackP mix; |
| |
| int size = vect.size(), i = 0; |
| |
| ColumnLevel *l = vect[0]->getColumnLevel(0); |
| if (!l) |
| return mix; |
| |
| TXshSoundLevel *soundLevel = l->getSoundLevel(); |
| assert(soundLevel); |
| |
| if (fps == -1) |
| fps = soundLevel->getFrameRate(); |
| if (fromFrame == -1) |
| fromFrame = 0; |
| if (toFrame == -1) |
| toFrame = getXsheet()->getFrameCount(); |
| |
| if (!soundLevel->getSoundTrack()) |
| return mix; |
| TSoundTrackFormat format = soundLevel->getSoundTrack()->getFormat(); |
| |
| TXshSoundColumn *c = 0; |
| int j; |
| for (j = 0; j < size; ++j) { |
| TXshSoundColumn *oldC = c; |
| c = vect[j]; |
| if (j == 0) { |
| mix = c->getOverallSoundTrack(fromFrame, toFrame, fps, format); |
| TSoundTrackP mixedTrack = TSoundTrack::create(mix->getFormat(), mix->getSampleCount()); |
| mix = TSop::mix(mixedTrack, mix, 1.0, c->getVolume()); |
| continue; |
| } |
| assert(oldC); |
| if (c->getVolume() == 0 || c->isEmpty()) { |
| c = oldC; |
| continue; |
| } |
| mix = TSop::mix(mix, c->getOverallSoundTrack(fromFrame, toFrame, fps, format), 1.0, c->getVolume()); |
| } |
| |
| |
| TSoundTrackFormat fmt = mix->getFormat(); |
| if (fmt.m_bitPerSample != 16) |
| fmt.m_bitPerSample = 16; |
| mix = TSop::convert(mix, fmt); |
| return mix; |
| } |
| |
| PERSIST_IDENTIFIER(TXshSoundColumn, "soundColumn") |
| |