1
0
mirror of https://github.com/cookiengineer/audacity synced 2025-05-06 14:52:34 +02:00

Merge branch 'master' into head

This commit is contained in:
Paul Licameli 2017-03-31 17:46:47 -04:00
commit 699b9d0517
43 changed files with 1638 additions and 1825 deletions

1
.gitignore vendored
View File

@ -177,6 +177,7 @@ win/Debug
win/Release
win/Projects/*/Debug
win/Projects/*/Release
win/.vs/
# All those help files
help/manual*

View File

@ -70,7 +70,9 @@ public:
sampleCount ( int v ) : value { v } {}
sampleCount ( unsigned v ) : value { v } {}
sampleCount ( long v ) : value { v } {}
sampleCount ( unsigned long v ) : value { v } {}
// unsigned long is 64 bit on some platforms. Let it narrow.
sampleCount ( unsigned long v ) : value ( v ) {}
// Beware implicit conversions from floating point values!
// Otherwise the meaning of binary operators with sampleCount change

File diff suppressed because it is too large Load Diff

View File

@ -3,10 +3,10 @@
# Antonio Paniagua Navarro <aplist@gmail.com>, 2011, 2012, 2013, 2014, 2015, 2016.
msgid ""
msgstr ""
"Project-Id-Version: Audacity 2.0.x\n"
"Project-Id-Version: Audacity 2.2.x\n"
"Report-Msgid-Bugs-To: audacity-translation@lists.sourceforge.net\n"
"POT-Creation-Date: 2017-03-18 18:41+0000\n"
"PO-Revision-Date: 2016-11-22 17:44+0100\n"
"PO-Revision-Date: 2017-03-30 02:21-0000\n"
"Last-Translator: Antonio Paniagua Navarro <aplist@gmail.com>\n"
"Language-Team: Spanish <audacity-translation@lists.sourceforge.net>\n"
"Language: es\n"
@ -14,7 +14,7 @@ msgstr ""
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
"X-Generator: Lokalize 1.5\n"
"X-Generator: Poedit 1.6.9\n"
#: lib-src/FileDialog/gtk/FileDialogPrivate.cpp:75
#, c-format
@ -3812,7 +3812,7 @@ msgstr "Pistas seleccionadas silenciadas durante %.2f segundos en %.2f"
#: src/Menus.cpp:4772 src/effects/Silence.h:22
msgid "Silence"
msgstr "Silenciar"
msgstr "Silencio"
#: src/Menus.cpp:4803
msgid "Duplicated"

View File

@ -2218,8 +2218,8 @@ msgid ""
"More:</b> Visit our [[http://wiki.audacityteam.org/index.php|Wiki]] for "
"tips, tricks, extra tutorials and effects plug-ins."
msgstr ""
"Di piiù:</b> Visita il nostro [[http://wiki.audacityteam.org/index.php|"
"Wiki]] per suggerimenti, trucchi, altri tutorial plug-in effetti."
"Di più:</b> Visita il nostro [[http://wiki.audacityteam.org/index.php|"
"Wiki]] per suggerimenti, trucchi, altri tutorial ed effetti audio."
#: src/HelpText.cpp:223
msgid ""
@ -3646,7 +3646,7 @@ msgstr "Nessuna traccia etichetta"
#: src/Menus.cpp:2716
msgid "no label track at or below focused track"
msgstr "nessuna etiichetta traccia nella o sotto la traccia evidenziata"
msgstr "nessuna etichetta traccia nella o sotto la traccia evidenziata"
#: src/Menus.cpp:2749
msgid "no labels in label track"
@ -8228,7 +8228,7 @@ msgstr "I passi per blocco sono troppo pochi per i tipi finestra."
#: src/effects/NoiseReduction.cpp:585
msgid "Steps per block cannot exceed the window size."
msgstr "I passi per blocco non possono superare la dimensione finestra."
msgstr "I passi per blocco non possono superare la dimensione della finestra."
#: src/effects/NoiseReduction.cpp:590
msgid "Median method is not implemented for more than four steps per window."
@ -11258,7 +11258,7 @@ msgid ""
"Error while writing %s file (disk full?).\n"
"Libsndfile says \"%s\""
msgstr ""
"Errore nella scrittura del file %s (diisco pienol?).\n"
"Errore durante la scrittura del file %s (disco pieno?).\n"
"Libsndfile indica \"%s\""
#: src/import/Import.cpp:508
@ -12386,7 +12386,7 @@ msgstr "Dispositivo:"
#: src/prefs/MidiIOPrefs.cpp:146
msgid "MIDI Synthesizer Latency (ms):"
msgstr "Latenza Sintetiizzatore MIDI (ms):"
msgstr "Latenza Sintetizzatore MIDI (ms):"
#: src/prefs/MidiIOPrefs.cpp:184
msgid "No MIDI interfaces"

File diff suppressed because it is too large Load Diff

View File

@ -9,7 +9,7 @@ msgstr ""
"Project-Id-Version: Audacity 2.0.0\n"
"Report-Msgid-Bugs-To: audacity-translation@lists.sourceforge.net\n"
"POT-Creation-Date: 2017-03-18 18:41+0000\n"
"PO-Revision-Date: 2017-02-13 19:31+0200\n"
"PO-Revision-Date: 2017-03-21 19:14+0200\n"
"Last-Translator: Yuri Chornoivan <yurchor@ukr.net>\n"
"Language-Team: Ukrainian <translation@linux.org.ua>\n"
"Language: uk\n"
@ -423,7 +423,7 @@ msgstr "Зупинити скрипт"
#: src/AboutDialog.cpp:94
msgid "Check Online"
msgstr ""
msgstr "У інтернеті"
#: src/AboutDialog.cpp:103
msgid "quality assurance"
@ -1136,9 +1136,8 @@ msgid "Could not enumerate files in auto save directory."
msgstr "Неможливо скласти список файлів у теці автозбереження."
#: src/AutoRecovery.cpp:760
#, fuzzy
msgid "Error Decoding File"
msgstr "Помилка під час спроби декодування файла"
msgstr "Помилка під час декодування файла"
#: src/BatchCommandDialog.cpp:60 src/BatchCommandDialog.cpp:64
#: src/BatchCommandDialog.cpp:65
@ -1486,9 +1485,8 @@ msgstr ""
"іншу теку для тимчасових файлів у діалоговому вікні налаштовування програми."
#: src/DirManager.cpp:424
#, fuzzy
msgid "Cleaning project temporary files"
msgstr "Вилучення тимчасових файлів"
msgstr "Вилучаємо тимчасові файли проекту"
#: src/DirManager.cpp:437
msgid "Cleaning up temporary files"
@ -2169,25 +2167,32 @@ msgstr "Відсутня локальна довідка"
#: src/HelpText.cpp:198
msgid "Get the Official Released Version of Audacity"
msgstr ""
msgstr "Отримати офіційну випущену версію Audacity"
#: src/HelpText.cpp:200
msgid ""
"<br><br>The version of Audacity you are using is an <b>Alpha test version</"
"b>."
msgstr ""
"<br><br>Версія Audacity, якою ви користуєтеся є <b>попередньою тестовою "
"версією (Alpha)</b>."
#: src/HelpText.cpp:201
msgid ""
"We strongly recommend that you use our latest stable released version, which "
"has full documentation and support.<br><br>"
msgstr ""
"Ми наполегливо рекомендуємо вам скористатися найсвіжішою стабільною версією "
"програми, яку повністю документовано і яка супроводжується розробниками.<br><"
"br>"
#: src/HelpText.cpp:202
msgid ""
"You can help us get Audacity ready for release by joining our [[http://www."
"audacityteam.org/community/|community]].<hr><br><br>"
msgstr ""
"Ви можете допомогти нам поліпшити Audacity до випуску, долучившись до нашої "
"[[http://www.audacityteam.org/community/|community]].<hr><br><br>"
#: src/HelpText.cpp:205
msgid "How to get help"
@ -2516,9 +2521,8 @@ msgstr ""
"%s (%s)."
#: src/Legacy.cpp:263
#, fuzzy
msgid "Error Converting Legacy Project File"
msgstr "Помилка під час спроби збереження файла проекту"
msgstr "Помилка під час спроби перетворити застарілий файл проекту"
#: src/Legacy.cpp:304
#, c-format
@ -9709,17 +9713,15 @@ msgstr ""
"до кодування Latin-1]"
#: src/effects/nyquist/Nyquist.cpp:1638
#, fuzzy, c-format
#, c-format
msgid ""
"Bad Nyquist 'control' type specification: '%s' in plug-in file '%s'.\n"
"Control not created."
msgstr ""
"Помилкова специфікація керування «control» Nyquist: «%s» у файлі додатка "
"«%s».\n"
"Керування не створено."
"Помилкова специфікація керування «control» Nyquist: «%s» у файлі додатка «%"
"s».\nКерування не створено."
#: src/effects/nyquist/Nyquist.cpp:1746
#, fuzzy
msgid ""
"Your code looks like SAL syntax, but there is no 'return' statement.\n"
"For SAL, use a return statement such as:\n"
@ -9729,11 +9731,9 @@ msgid ""
" ."
msgstr ""
"Синтаксичні конструкції вашого коду нагадують SAL, але не вказано інструкції "
"return. Вам слід або скористатися інструкцією return ось так:\n"
"\treturn s * 0.1\n"
"для SAL, або почати з дужки, ось так:\n"
"\t(mult s 0.1)\n"
"як це робиться у LISP."
"return. Вам слід або скористатися інструкцією return ось так:\n\treturn "
"*track* * 0.1\nдля SAL, або почати з дужки, ось так:\n\t(mult *track* "
"0.1)\nяк це робиться у LISP."
#: src/effects/nyquist/Nyquist.cpp:1749
msgid "Error in Nyquist code"
@ -9945,9 +9945,8 @@ msgid "Error writing to file: \"%s\""
msgstr "Помилка під час спроби записати дані до файла «%s»"
#: src/effects/VST/VSTEffect.cpp:3565
#, fuzzy
msgid "Error Saving Effect Presets"
msgstr "Помилка під час спроби збереження шаблону VST"
msgstr "Помилка під час спроби зберегти шаблони ефектів"
#: src/effects/VST/VSTEffect.cpp:3686
#, c-format
@ -10303,9 +10302,8 @@ msgstr "Відкрити вікно нетипових параметрів фо
#: src/export/ExportFFmpegDialogs.cpp:498
#: src/export/ExportFFmpegDialogs.cpp:522
#, fuzzy
msgid "Error Saving FFmpeg Presets"
msgstr "Помилка під час спроби збереження шаблону VST"
msgstr "Помилка під час спроби зберегти шаблони FFmpeg"
#: src/export/ExportFFmpegDialogs.cpp:568
#, c-format
@ -14283,9 +14281,8 @@ msgid "NaN"
msgstr "Не число"
#: src/widgets/numformatter.cpp:146
#, fuzzy
msgid "Infinity"
msgstr "-Нескінченність"
msgstr "Нескінченність"
#: src/widgets/numformatter.cpp:150
msgid "-Infinity"

View File

@ -12,7 +12,7 @@ msgstr ""
"Project-Id-Version: Audacity\n"
"Report-Msgid-Bugs-To: audacity-translation@lists.sourceforge.net\n"
"POT-Creation-Date: 2017-03-18 18:41+0000\n"
"PO-Revision-Date: 2016-07-03 12:19+0000\n"
"PO-Revision-Date: 2017-03-27 15:01+0800\n"
"Last-Translator: zhangmin <zm1990s@gmail.com>\n"
"Language-Team: Chinese (http://www.transifex.com/klyok/audacity/language/"
"zh/)\n"
@ -21,6 +21,7 @@ msgstr ""
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=1; plural=0;\n"
"X-Generator: Poedit 1.8.12\n"
#: lib-src/FileDialog/gtk/FileDialogPrivate.cpp:75
#, c-format
@ -39,17 +40,16 @@ msgstr "请选择一个已存在的文件。"
#: src/AutoRecovery.cpp:195 src/Menus.cpp:4294 src/Menus.cpp:4306
#: src/Menus.cpp:7005 src/Menus.cpp:7084 src/Project.cpp:3124
#: src/Project.cpp:5118 src/Project.cpp:5137 src/TimerRecordDialog.cpp:471
#: src/TimerRecordDialog.cpp:649 src/TrackPanel.cpp:8489
#: src/WaveTrack.cpp:1316 src/WaveTrack.cpp:1335 src/WaveTrack.cpp:2487
#: src/effects/Contrast.cpp:56 src/effects/Contrast.cpp:75
#: src/effects/Contrast.cpp:82 src/effects/Contrast.cpp:96
#: src/effects/Effect.cpp:2584 src/effects/Generator.cpp:59
#: src/effects/nyquist/Nyquist.cpp:411 src/export/ExportFFmpeg.cpp:842
#: src/export/ExportMP2.cpp:229 src/prefs/DirectoriesPrefs.cpp:210
#: src/prefs/DirectoriesPrefs.cpp:239 src/prefs/KeyConfigPrefs.cpp:509
#: src/prefs/KeyConfigPrefs.cpp:523 src/prefs/KeyConfigPrefs.cpp:548
#: src/prefs/KeyConfigPrefs.cpp:1038 src/toolbars/ControlToolBar.cpp:686
#: src/toolbars/ControlToolBar.cpp:1122
#: src/TimerRecordDialog.cpp:649 src/TrackPanel.cpp:8489 src/WaveTrack.cpp:1316
#: src/WaveTrack.cpp:1335 src/WaveTrack.cpp:2487 src/effects/Contrast.cpp:56
#: src/effects/Contrast.cpp:75 src/effects/Contrast.cpp:82
#: src/effects/Contrast.cpp:96 src/effects/Effect.cpp:2584
#: src/effects/Generator.cpp:59 src/effects/nyquist/Nyquist.cpp:411
#: src/export/ExportFFmpeg.cpp:842 src/export/ExportMP2.cpp:229
#: src/prefs/DirectoriesPrefs.cpp:210 src/prefs/DirectoriesPrefs.cpp:239
#: src/prefs/KeyConfigPrefs.cpp:509 src/prefs/KeyConfigPrefs.cpp:523
#: src/prefs/KeyConfigPrefs.cpp:548 src/prefs/KeyConfigPrefs.cpp:1038
#: src/toolbars/ControlToolBar.cpp:686 src/toolbars/ControlToolBar.cpp:1122
msgid "Error"
msgstr "错误"
@ -179,14 +179,12 @@ msgstr "脚本"
msgid "Output"
msgstr "输出"
#: lib-src/mod-nyq-bench/NyqBench.cpp:1051
#: src/effects/nyquist/Nyquist.cpp:2214
#: lib-src/mod-nyq-bench/NyqBench.cpp:1051 src/effects/nyquist/Nyquist.cpp:2214
msgid "Load Nyquist script"
msgstr "加载 Nyquist 脚本"
#: lib-src/mod-nyq-bench/NyqBench.cpp:1054
#: lib-src/mod-nyq-bench/NyqBench.cpp:1100
#: src/effects/nyquist/Nyquist.cpp:2239
#: lib-src/mod-nyq-bench/NyqBench.cpp:1100 src/effects/nyquist/Nyquist.cpp:2239
msgid "Nyquist scripts (*.ny)|*.ny|Lisp scripts (*.lsp)|*.lsp|All files|*"
msgstr "Nyquist 脚本 (*.ny)|*.ny|Lisp 脚本 (*.lsp)|*.lsp|所有文件|*"
@ -204,8 +202,7 @@ msgstr "脚本未被保存。"
msgid "Warning"
msgstr "警告"
#: lib-src/mod-nyq-bench/NyqBench.cpp:1097
#: src/effects/nyquist/Nyquist.cpp:2236
#: lib-src/mod-nyq-bench/NyqBench.cpp:1097 src/effects/nyquist/Nyquist.cpp:2236
msgid "Save Nyquist script"
msgstr "保存 Nyquist 脚本"
@ -223,11 +220,11 @@ msgstr "Tango 图标库 (工具栏图标)"
#: lib-src/mod-nyq-bench/NyqBench.cpp:1417
msgid "Leland Lucius"
msgstr "Leland Lucius"
msgstr "利兰卢修斯\\N"
#: lib-src/mod-nyq-bench/NyqBench.cpp:1418
msgid "(C) 2009 by Leland Lucius"
msgstr "(C) 2009 by Leland Lucius"
msgstr "(C) 2009 by 利兰卢修斯\\N"
#: lib-src/mod-nyq-bench/NyqBench.cpp:1419
msgid ""
@ -423,7 +420,7 @@ msgstr "停止脚本"
#: src/AboutDialog.cpp:94
msgid "Check Online"
msgstr ""
msgstr "在线检查"
#: src/AboutDialog.cpp:103
msgid "quality assurance"
@ -431,7 +428,7 @@ msgstr "质量保证"
#: src/AboutDialog.cpp:104
msgid "system administration"
msgstr ""
msgstr "系统管理\\N"
#: src/AboutDialog.cpp:105 src/AboutDialog.cpp:108 src/AboutDialog.cpp:110
#: src/AboutDialog.cpp:112 src/AboutDialog.cpp:118 src/AboutDialog.cpp:120
@ -457,28 +454,28 @@ msgstr "包络线"
#: src/AboutDialog.cpp:106 src/AboutDialog.cpp:127
msgid "co-founder and developer"
msgstr ""
msgstr "联合创始人和开发者\\N"
#: src/AboutDialog.cpp:109 src/AboutDialog.cpp:113 src/AboutDialog.cpp:131
#: src/AboutDialog.cpp:132
msgid "documentation and support"
msgstr ""
msgstr "文档和支持\\N"
#: src/AboutDialog.cpp:119
msgid "documentation and support, French"
msgstr ""
msgstr "文档和支持,法语"
#: src/AboutDialog.cpp:137
msgid "accessibility advisor"
msgstr ""
msgstr "无障碍顾问"
#: src/AboutDialog.cpp:156
msgid "graphic artist"
msgstr ""
msgstr "图形艺术家\\N"
#: src/AboutDialog.cpp:163
msgid "composer"
msgstr ""
msgstr "作曲家\\N"
#: src/AboutDialog.cpp:166
#, fuzzy
@ -513,7 +510,6 @@ msgstr ""
"\">Audacity</a>支持Windows、Mac OS X和GNU/Linux(以及其它的Unix类操作系统)。"
#: src/AboutDialog.cpp:337
#, fuzzy
msgid ""
"If you find a bug or have a suggestion for us, please write, in English, to "
"our [[mailto:feedback@audacityteam.org|feedback address]]. For help, view "
@ -522,8 +518,8 @@ msgid ""
msgstr ""
"如果你找到一个bug或者有建议给我们请用英语书写发邮件到 <a href=\"mailto:"
"feedback@audacityteam.org\">反馈地址</a>。如果想获得帮助,查看小贴士和小技"
"巧,请访问<a href=\"http://wiki.audacityteam.org/\">wiki</a> 或 <a href="
"\"http://forum.audacityteam.org/\">论坛</a>。"
"巧,请访问<a href=\"http://wiki.audacityteam.org/\">audacity维基</a> 或 <a "
"href=\"http://forum.audacityteam.org/\">audacity论坛</a>。"
#. i18n-hint: The translation of "translator_credits" will appear
#. * in the credits in the About Audacity window. Use this to add
@ -555,11 +551,11 @@ msgstr "Audacity开发人员"
#: src/AboutDialog.cpp:368
msgid "Emeritus:"
msgstr ""
msgstr "名誉:"
#: src/AboutDialog.cpp:369
msgid "Distinguished Audacity Team members, not currently active"
msgstr ""
msgstr "杰出的Audacity团队成员目前不活跃"
#: src/AboutDialog.cpp:372
#, fuzzy
@ -567,9 +563,8 @@ msgid "Contributors"
msgstr "其他贡献者"
#: src/AboutDialog.cpp:375
#, fuzzy
msgid "Translators"
msgstr "播录"
msgstr "翻译"
#: src/AboutDialog.cpp:379 src/prefs/LibraryPrefs.cpp:49
msgid "Libraries"
@ -596,6 +591,7 @@ msgid ""
"Audacity website: [[http://www.audacityteam.org/|http://www.audacityteam."
"org/]]"
msgstr ""
"Audacity网站:[[http://www.audacityteam.org/|http://www.audacityteam.org/]]"
#. i18n-hint: Information about when audacity was compiled
#: src/AboutDialog.cpp:446 src/AboutDialog.cpp:459 src/AboutDialog.cpp:631
@ -760,7 +756,7 @@ msgstr "文件丢失"
#: src/AudacityApp.cpp:1047
#, c-format
msgid "Language \"%s\" is unknown"
msgstr ""
msgstr "语言 \"%s\"未知"
#: src/AudacityApp.cpp:1170
msgid "Report generated to:"
@ -939,8 +935,8 @@ msgstr "Audacity日志"
msgid "&Save..."
msgstr "保存...(&S)"
#: src/AudacityLogger.cpp:199 src/Tags.cpp:883
#: src/prefs/KeyConfigPrefs.cpp:273 src/prefs/KeyConfigPrefs.cpp:781
#: src/AudacityLogger.cpp:199 src/Tags.cpp:883 src/prefs/KeyConfigPrefs.cpp:273
#: src/prefs/KeyConfigPrefs.cpp:781
msgid "Cl&ear"
msgstr "清除(&e)"
@ -2119,25 +2115,27 @@ msgstr "没有本地帮助"
#: src/HelpText.cpp:198
msgid "Get the Official Released Version of Audacity"
msgstr ""
msgstr "获得Audacity的官方发布版本"
#: src/HelpText.cpp:200
msgid ""
"<br><br>The version of Audacity you are using is an <b>Alpha test version</"
"b>."
msgstr ""
msgstr "<br><br>您所使用的Audacity版本是 <b>内部测试版</b>."
#: src/HelpText.cpp:201
msgid ""
"We strongly recommend that you use our latest stable released version, which "
"has full documentation and support.<br><br>"
msgstr ""
msgstr "我们强烈建议您使用我们最新的稳定版本,它具有完整的文档和支持。<br><br>"
#: src/HelpText.cpp:202
msgid ""
"You can help us get Audacity ready for release by joining our [[http://www."
"audacityteam.org/community/|community]].<hr><br><br>"
msgstr ""
"您可以通过加入我们来帮助我们让Audacity准备发布 [[http://www.audacityteam.org/"
"community/|audacity社区]].<hr><br><br>"
#: src/HelpText.cpp:205
#, fuzzy
@ -2305,12 +2303,12 @@ msgstr "指定新文件名:"
#. i18n-hint: An opening parenthesis, in some languages a right parenthesis
#: src/Internat.cpp:265
msgid "("
msgstr ""
msgstr "("
#. i18n-hint: A closing parenthesis, in some languages a left parenthesis
#: src/Internat.cpp:267
msgid ")"
msgstr ""
msgstr ")"
#: src/LabelDialog.cpp:102
msgid "Edit Labels"
@ -2732,7 +2730,7 @@ msgstr "光标移至音轨末(&E)"
#: src/Menus.cpp:561
msgid "Cursor to Stored &Cursor Position"
msgstr ""
msgstr "游标存储光标位置"
#: src/Menus.cpp:567
msgid "In All &Tracks"
@ -2768,15 +2766,15 @@ msgstr "到音轨结束点(&E)"
#: src/Menus.cpp:600
msgid "Store Re&gion"
msgstr ""
msgstr "存储区域"
#: src/Menus.cpp:603
msgid "Retrieve Regio&n"
msgstr ""
msgstr "检索区域&n"
#: src/Menus.cpp:606
msgid "Store Cursor Pos&ition"
msgstr ""
msgstr "存储光标位置"
#: src/Menus.cpp:614
msgid "Pla&y Region"
@ -2976,7 +2974,7 @@ msgstr "追加录音(&d)"
#: src/Menus.cpp:788
msgid "Pinned Recording/Playback &Head"
msgstr ""
msgstr "固定录音/播放头"
#: src/Menus.cpp:793
msgid "&Overdub (on/off)"
@ -3115,7 +3113,7 @@ msgstr "编辑标记(&E)"
#: src/Menus.cpp:931
msgid "&Type to Create a Label (on/off)"
msgstr ""
msgstr "&键入以创建标签(开/关)"
#: src/Menus.cpp:938
msgid "S&ort Tracks"
@ -3185,7 +3183,7 @@ msgstr "缩放"
#: src/Menus.cpp:1055
msgid "&Bring All to Front"
msgstr ""
msgstr "全部带到前面"
#: src/Menus.cpp:1066 src/Menus.cpp:1069 src/effects/Contrast.cpp:298
msgid "&Help"
@ -4105,7 +4103,7 @@ msgid ""
"Timer Recording cannot be used with more than one open project.\n"
"\n"
"Please close any additional projects and try again."
msgstr ""
msgstr "定时录制不能与多个打开的项目一起使用。请关闭任何其他项目,然后重试。"
#: src/Menus.cpp:6547 src/Menus.cpp:6558 src/TimerRecordDialog.cpp:658
#, fuzzy
@ -4117,7 +4115,7 @@ msgid ""
"Timer Recording cannot be used while you have unsaved changes.\n"
"\n"
"Please save or close this project and try again."
msgstr ""
msgstr "在保存更改时,无法使用定时录像。请保存或关闭此项目,然后重试。"
#: src/Menus.cpp:6731
msgid "Edited labels"
@ -4817,7 +4815,7 @@ msgstr "删除轨道"
#: src/Project.cpp:5605
msgid "Less than 1 minute"
msgstr ""
msgstr "不到1分钟"
#. i18n-hint: A time in hours and minutes. Only translate the "and".
#: src/Project.cpp:5618
@ -5299,7 +5297,7 @@ msgstr "持续时间错误"
#: src/TimerRecordDialog.cpp:374
msgid "Automatic Save path is invalid."
msgstr ""
msgstr "自动保存路径无效。"
#: src/TimerRecordDialog.cpp:375
#, fuzzy
@ -5308,7 +5306,7 @@ msgstr "持续时间错误"
#: src/TimerRecordDialog.cpp:381
msgid "Automatic Export path is invalid."
msgstr ""
msgstr "自动导出路径无效。"
#: src/TimerRecordDialog.cpp:382
#, fuzzy
@ -5317,7 +5315,7 @@ msgstr "持续时间错误"
#: src/TimerRecordDialog.cpp:419
msgid "Timer Recording Disk Space Warning"
msgstr ""
msgstr "计时器记录磁盘空间通知"
#: src/TimerRecordDialog.cpp:461 src/TimerRecordDialog.cpp:869
#, fuzzy
@ -5343,11 +5341,11 @@ msgstr "录制结束"
#: src/TimerRecordDialog.cpp:528 src/TimerRecordDialog.cpp:1006
msgid "Automatic Save enabled:\n"
msgstr ""
msgstr "自动保存启用:\n"
#: src/TimerRecordDialog.cpp:529 src/TimerRecordDialog.cpp:1007
msgid "Automatic Export enabled:\n"
msgstr ""
msgstr "自动导出启用:\n"
#: src/TimerRecordDialog.cpp:530 src/TimerRecordDialog.cpp:1008
#: src/TimerRecordDialog.cpp:1051
@ -5449,7 +5447,7 @@ msgstr "选项:"
#: src/TimerRecordDialog.cpp:900
msgid "Do nothing"
msgstr ""
msgstr "什么都不做"
#: src/TimerRecordDialog.cpp:901
#, fuzzy
@ -5458,11 +5456,11 @@ msgstr "退出 Audacity"
#: src/TimerRecordDialog.cpp:902
msgid "Restart system"
msgstr ""
msgstr "重启系统"
#: src/TimerRecordDialog.cpp:903
msgid "Shutdown system"
msgstr ""
msgstr "关机系统"
#: src/TimerRecordDialog.cpp:913
#, fuzzy
@ -5483,7 +5481,7 @@ msgstr "录制音频"
msgid ""
"Scheduled to stop at:\n"
"\n"
msgstr ""
msgstr "计划停在:\n"
#: src/TimerRecordDialog.cpp:1024
msgid "Audacity Timer Record - Waiting for Start"
@ -5578,7 +5576,7 @@ msgstr "格式(&F)"
#: src/TrackPanel.cpp:640
msgid "Rat&e"
msgstr ""
msgstr "Rat&e"
#: src/TrackPanel.cpp:645
msgid "Up &Octave"
@ -5651,13 +5649,13 @@ msgstr "单击在垂直方向放大按住Shift键单击缩小拖拽创建
#: src/TrackPanel.cpp:1410
#, c-format
msgid "%s to select or deselect track. Drag up or down to change track order."
msgstr ""
msgstr "%s选择或取消选择轨道。向上或向下拖动以更改轨道顺序。"
#. i18n-hint: %s is replaced by (translation of) 'Ctrl-Click' on windows, 'Command-Click' on Mac
#: src/TrackPanel.cpp:1417
#, c-format
msgid "%s to select or deselect track."
msgstr ""
msgstr "%s选择或取消选择轨道。"
#: src/TrackPanel.cpp:1432
msgid "Click and drag to adjust relative size of stereo tracks."
@ -5910,10 +5908,12 @@ msgid ""
"To change Spectrogram Settings, stop any\n"
".playing or recording first."
msgstr ""
"要更改谱图设置,请停止任何\n"
"播放或录音."
#: src/TrackPanel.cpp:8200
msgid "Stop the Audio First"
msgstr ""
msgstr "先停止音频"
#: src/TrackPanel.cpp:8294
#, c-format
@ -6304,7 +6304,7 @@ msgstr "高音"
#: src/effects/BassTreble.cpp:47
msgid "Link Sliders"
msgstr ""
msgstr "链接滑块"
#: src/effects/BassTreble.cpp:92
#, fuzzy
@ -6313,7 +6313,7 @@ msgstr "选区的左端收缩"
#: src/effects/BassTreble.cpp:209
msgid "Tone controls"
msgstr ""
msgstr "音调控制"
#: src/effects/BassTreble.cpp:218
#, fuzzy
@ -6339,7 +6339,7 @@ msgstr "电平"
#: src/effects/BassTreble.cpp:261
msgid "&Link Volume control to Tone controls"
msgstr ""
msgstr "&并将音量控制连接到音调控制"
#: src/effects/BassTreble.h:26
msgid "Bass and Treble"
@ -6352,7 +6352,7 @@ msgstr "百分比"
#: src/effects/ChangePitch.cpp:58 src/effects/ChangeTempo.cpp:52
msgid "SBSMS"
msgstr ""
msgstr "吕雪莉"
#: src/effects/ChangePitch.cpp:126
msgid "Change the pitch of a track without changing its tempo"
@ -6360,7 +6360,7 @@ msgstr "改变音高,维持节奏不变"
#: src/effects/ChangePitch.cpp:188
msgid "High Quality Pitch Change"
msgstr ""
msgstr "高质量的音高变化"
#: src/effects/ChangePitch.cpp:245
msgid "Change Pitch without Changing Tempo"
@ -6430,7 +6430,7 @@ msgstr "改变百分比"
#: src/effects/ChangePitch.cpp:331 src/effects/ChangeTempo.cpp:278
msgid "Use high quality stretching (slow)"
msgstr ""
msgstr "使用高品质的拉伸 (慢)"
#: src/effects/ChangePitch.h:39
msgid "Change Pitch"
@ -6716,7 +6716,7 @@ msgstr "一次只能测量一个音轨。"
msgid ""
"Invalid audio selection.\n"
"Please ensure that audio is selected."
msgstr ""
msgstr "音频选择无效请确保选择音频。"
#: src/effects/Contrast.cpp:82
msgid ""
@ -6813,7 +6813,7 @@ msgstr "背景结束时间"
#: src/effects/Contrast.cpp:380
msgid "Background higher than foreground"
msgstr ""
msgstr "背景高于前景"
#: src/effects/Contrast.cpp:383
msgid "WCAG2 Pass"
@ -6972,19 +6972,19 @@ msgstr "确认覆盖"
#: src/effects/Distortion.cpp:65
msgid "Hard Overdrive"
msgstr ""
msgstr "硬盘超速:"
#: src/effects/Distortion.cpp:66
msgid "Cubic Curve (odd harmonics)"
msgstr ""
msgstr "立方曲线(奇次谐波)"
#: src/effects/Distortion.cpp:67
msgid "Even Harmonics"
msgstr ""
msgstr "甚至谐波"
#: src/effects/Distortion.cpp:68
msgid "Expand and Compress"
msgstr ""
msgstr "展开和压缩"
#: src/effects/Distortion.cpp:69 src/effects/Leveller.h:21
msgid "Leveller"
@ -6992,11 +6992,11 @@ msgstr "水平器"
#: src/effects/Distortion.cpp:70
msgid "Rectifier Distortion"
msgstr ""
msgstr "整流器失真"
#: src/effects/Distortion.cpp:71
msgid "Hard Limiter 1413"
msgstr ""
msgstr "硬限制1413"
#: src/effects/Distortion.cpp:78 src/effects/Noise.cpp:48
msgid "Type"
@ -7004,7 +7004,7 @@ msgstr "类型"
#: src/effects/Distortion.cpp:79
msgid "DC Block"
msgstr ""
msgstr "直流块"
#: src/effects/Distortion.cpp:80
#, fuzzy
@ -7029,84 +7029,84 @@ msgstr "重复"
#: src/effects/Distortion.cpp:102
#, no-c-format
msgid "Hard clip -12dB, 80% make-up gain"
msgstr ""
msgstr "硬夹80%增益12dB化妆"
#: src/effects/Distortion.cpp:104
#, no-c-format
msgid "Soft clip -12dB, 80% make-up gain"
msgstr ""
msgstr "软夹80%增益12dB化妆"
#: src/effects/Distortion.cpp:105
msgid "Fuzz Box"
msgstr ""
msgstr "绒盒"
#: src/effects/Distortion.cpp:106
msgid "Walkie-talkie"
msgstr ""
msgstr "对讲机"
#: src/effects/Distortion.cpp:107
msgid "Blues drive sustain"
msgstr ""
msgstr "布鲁斯驱动支持"
#: src/effects/Distortion.cpp:108
msgid "Light Crunch Overdrive"
msgstr ""
msgstr "光紧缩超速"
#: src/effects/Distortion.cpp:109
msgid "Heavy Overdrive"
msgstr ""
msgstr "重超速"
#: src/effects/Distortion.cpp:110
msgid "3rd Harmonic (Perfect Fifth)"
msgstr ""
msgstr "第三谐波(完美第五)"
#: src/effects/Distortion.cpp:111
msgid "Valve Overdrive"
msgstr ""
msgstr "阀驱动"
#: src/effects/Distortion.cpp:112
msgid "2nd Harmonic (Octave)"
msgstr ""
msgstr "第二谐波(倍频程)"
#: src/effects/Distortion.cpp:113
msgid "Gated Expansion Distortion"
msgstr ""
msgstr "门控膨胀变形"
#: src/effects/Distortion.cpp:114
msgid "Leveller, Light, -70dB noise floor"
msgstr ""
msgstr "矫直机、光、70分贝噪声地板"
#: src/effects/Distortion.cpp:115
msgid "Leveller, Moderate, -70dB noise floor"
msgstr ""
msgstr "矫直机温和70分贝噪声地板"
#: src/effects/Distortion.cpp:116
msgid "Leveller, Heavy, -70dB noise floor"
msgstr ""
msgstr "矫直机70分贝噪声地板"
#: src/effects/Distortion.cpp:117
msgid "Leveller, Heavier, -70dB noise floor"
msgstr ""
msgstr "矫直机70分贝噪声地板"
#: src/effects/Distortion.cpp:118
msgid "Leveller, Heaviest, -70dB noise floor"
msgstr ""
msgstr "矫直机70分贝噪声地板"
#: src/effects/Distortion.cpp:119
msgid "Half-wave Rectifier"
msgstr ""
msgstr "半波整流"
#: src/effects/Distortion.cpp:120
msgid "Full-wave Rectifier"
msgstr ""
msgstr "全波整流"
#: src/effects/Distortion.cpp:121
msgid "Full-wave Rectifier (DC blocked)"
msgstr ""
msgstr "全波整流器(直流阻塞)"
#: src/effects/Distortion.cpp:122
msgid "Percussion Limiter"
msgstr ""
msgstr "冲击器"
#: src/effects/Distortion.cpp:127
#, fuzzy
@ -7120,7 +7120,7 @@ msgstr "要添加的重复次数:"
#: src/effects/Distortion.cpp:192
msgid "Waveshaping distortion effect"
msgstr ""
msgstr "波形失真影响"
#: src/effects/Distortion.cpp:344
#, fuzzy
@ -7129,7 +7129,7 @@ msgstr "插值类型"
#: src/effects/Distortion.cpp:348
msgid "DC blocking filter"
msgstr ""
msgstr "直流阻断滤波器"
#: src/effects/Distortion.cpp:355
#, fuzzy
@ -7148,11 +7148,11 @@ msgstr "破音"
#: src/effects/Distortion.cpp:676
msgid "Drive"
msgstr ""
msgstr "驱动"
#: src/effects/Distortion.cpp:677 src/effects/Distortion.cpp:691
msgid "Make-up Gain"
msgstr ""
msgstr "弥补增益"
#: src/effects/Distortion.cpp:688
#, fuzzy
@ -7161,14 +7161,14 @@ msgstr "静音阈值"
#: src/effects/Distortion.cpp:690
msgid "Hardness"
msgstr ""
msgstr "硬度"
#: src/effects/Distortion.cpp:704 src/effects/Distortion.cpp:718
#: src/effects/Distortion.cpp:732 src/effects/Distortion.cpp:746
#: src/effects/Distortion.cpp:760 src/effects/Distortion.cpp:774
#: src/effects/Distortion.cpp:802
msgid "Distortion amount"
msgstr ""
msgstr "变形量"
#: src/effects/Distortion.cpp:705 src/effects/Distortion.cpp:719
#: src/effects/Distortion.cpp:733 src/effects/Distortion.cpp:747
@ -7184,11 +7184,11 @@ msgstr "减小处理时间。"
#: src/effects/Distortion.cpp:761
msgid "Harmonic brightness"
msgstr ""
msgstr "谐波的亮度"
#: src/effects/Distortion.cpp:788
msgid "Levelling fine adjustment"
msgstr ""
msgstr "平微调"
#: src/effects/Distortion.cpp:790
#, fuzzy
@ -7197,7 +7197,7 @@ msgstr "调平度:"
#: src/effects/Distortion.cpp:814
msgid "dB Limit"
msgstr ""
msgstr "分贝限制"
#: src/effects/Distortion.cpp:816
#, fuzzy
@ -7211,17 +7211,17 @@ msgstr "保留噪音(&u)"
#: src/effects/Distortion.cpp:833
msgid " (Not Used):"
msgstr ""
msgstr "(未使用):"
#. i18n-hint: Control range.
#: src/effects/Distortion.cpp:838
msgid " (-100 to 0 dB):"
msgstr ""
msgstr "- 100至0分贝"
#. i18n-hint: Control range.
#: src/effects/Distortion.cpp:853
msgid " (-80 to -20 dB):"
msgstr ""
msgstr "- 80至20分贝"
#. i18n-hint: Control range.
#: src/effects/Distortion.cpp:864 src/effects/Distortion.cpp:875
@ -7232,7 +7232,7 @@ msgstr "(%) [-50到100]"
#. i18n-hint: Control range.
#: src/effects/Distortion.cpp:886
msgid " (0 to 5):"
msgstr ""
msgstr "0至5"
#: src/effects/Distortion.h:26
#, fuzzy
@ -7315,7 +7315,7 @@ msgstr "一遍遍地重复选中音频"
#: src/effects/Echo.cpp:102 src/effects/FindClipping.cpp:168
#: src/effects/Paulstretch.cpp:249
msgid "Requested value exceeds memory capacity."
msgstr ""
msgstr "请求值超过内存容量。"
#: src/effects/Echo.cpp:159
msgid "Delay time (seconds):"
@ -7341,6 +7341,8 @@ msgid ""
"\n"
"%s"
msgstr ""
"%s:无法加载下面的设置。将使用默认设置。\n"
"%s"
#. i18n-hint: Name of time display format that shows time in hours,
#. * minutes, seconds and samples (at the current project sample rate)
@ -7702,7 +7704,7 @@ msgstr "如果想应用均衡器,所有选择的轨道必须拥有相同的采
#: src/effects/Equalization.cpp:490
msgid "Track sample rate is too low for this effect."
msgstr ""
msgstr "跟踪采样率太低,这种效果。"
#: src/effects/Equalization.cpp:491
#, fuzzy
@ -8052,7 +8054,7 @@ msgstr "淡出"
#: src/effects/FindClipping.cpp:61
msgid "Creates labels where clipping is detected"
msgstr ""
msgstr "创建剪切检测到的标签"
#: src/effects/FindClipping.cpp:98
msgid "Clipping"
@ -8563,6 +8565,9 @@ msgid ""
"Try increasing the audio selection to at least %.1f seconds,\n"
"or reducing the 'Time Resolution' to less than %.1f seconds."
msgstr ""
"音频选择太短,无法预览。\n"
"尝试增加音频选择至少 %.1f seconds,\n"
" 或减少时间分辨率''小于 %.1f seconds."
#. i18n-hint: 'Time Resolution' is the name of a control in the Paulstretch effect.
#: src/effects/Paulstretch.cpp:291
@ -8573,6 +8578,8 @@ msgid ""
"For the current audio selection, the maximum\n"
"'Time Resolution' is %.1f seconds."
msgstr ""
"无法预览。\n"
"'Time Resolution' is %.1f seconds."
#. i18n-hint: 'Time Resolution' is the name of a control in the Paulstretch effect.
#: src/effects/Paulstretch.cpp:300
@ -8583,6 +8590,9 @@ msgid ""
"Try increasing the audio selection to at least %.1f seconds,\n"
"or reducing the 'Time Resolution' to less than %.1f seconds."
msgstr ""
"选择的时间分辨率太长。\n"
"尝试增加音频选择至少 %.1f seconds,\n"
"或减少“时间分辨率”小于 %.1f seconds."
#: src/effects/Paulstretch.h:19
msgid "Paulstretch"
@ -8878,7 +8888,7 @@ msgstr "反向"
#: src/effects/SBSMSEffect.h:38
msgid "SBSMS Time / Pitch Stretch"
msgstr ""
msgstr "吕雪莉时间/沥青拉伸"
#. i18n-hint: Butterworth is the name of the person after whom the filter type is named.
#: src/effects/ScienFilter.cpp:92
@ -9187,11 +9197,11 @@ msgstr "插值"
#: src/effects/ToneGen.cpp:132
msgid "Generates an ascending or descending tone of one of four types"
msgstr ""
msgstr "产生四种类型之一的升序或降序"
#: src/effects/ToneGen.cpp:133
msgid "Generates a constant frequency tone of one of four types"
msgstr ""
msgstr "产生四种类型之一的恒定频率音调"
#: src/effects/ToneGen.cpp:312
msgid "Waveform:"
@ -9268,7 +9278,7 @@ msgstr "自动减小指定音量以下片段的长度"
msgid ""
"When truncating independently, there may only be one selected audio track in "
"each Sync-Locked Track Group."
msgstr ""
msgstr "当独立截断时,每个同步锁定的轨道组中只能有一个选定的音轨。"
#: src/effects/TruncSilence.cpp:702
msgid "Detect Silence"
@ -9549,6 +9559,8 @@ msgid ""
"in the track Spectrogram settings and select the\n"
"frequency range for the effect to act on."
msgstr ""
"要使用“光谱效应”,请在轨道光谱图设置中启用“光谱选择”,并选择要作用的效果的频"
"率范围。"
#: src/effects/nyquist/Nyquist.cpp:621
msgid ""
@ -10798,7 +10810,7 @@ msgstr "立体声"
#: src/export/ExportMP3.cpp:427
msgid "Force export to mono"
msgstr ""
msgstr "强制输出到单声道"
#. i18n-hint: LAME is the name of an MP3 converter and should not be translated
#: src/export/ExportMP3.cpp:593
@ -11741,7 +11753,7 @@ msgstr "不可用 - 上面的位置不存在"
#: src/prefs/DirectoriesPrefs.cpp:208
#, c-format
msgid "Directory %s is not suitable (at risk of being cleaned out)"
msgstr ""
msgstr "目录 %s是不合适的 (冒被清理的危险)"
#: src/prefs/DirectoriesPrefs.cpp:216
#, c-format
@ -12732,11 +12744,11 @@ msgstr "轨道编号"
#: src/prefs/RecordingPrefs.cpp:159
msgid "Add System &Date"
msgstr ""
msgstr "添加系统和日期"
#: src/prefs/RecordingPrefs.cpp:163
msgid "Add System T&ime"
msgstr ""
msgstr "添加系统Time"
#: src/prefs/RecordingPrefs.cpp:170
msgid "Automated Recording Level Adjustment"
@ -13084,7 +13096,7 @@ msgstr "频谱图(&S)"
#: src/prefs/TracksPrefs.cpp:107
msgid "&Pinned Recording/Playback head"
msgstr ""
msgstr "&固定录音/播放头"
#: src/prefs/TracksPrefs.cpp:110
#, fuzzy
@ -13135,7 +13147,7 @@ msgstr "编辑一段会移动 其它片段(&M)"
#: src/prefs/TracksPrefs.cpp:159
msgid "&Type to create a label"
msgstr ""
msgstr "&键入以创建标签"
#: src/prefs/TracksPrefs.cpp:163
msgid "Enable scrolling left of &zero"
@ -13175,7 +13187,7 @@ msgstr "导出时混合到立体声(&S)"
#: src/prefs/WarningsPrefs.cpp:72
msgid "Mixing down on export (&Custom FFmpeg or external program)"
msgstr ""
msgstr "混合导出定制ffmpeg或外部程序"
#: src/prefs/WarningsPrefs.cpp:75
msgid "&Importing uncompressed audio files"
@ -13459,7 +13471,7 @@ msgstr "启动脚本"
#.
#: src/toolbars/ScrubbingToolBar.cpp:170
msgid "Stop Seeking"
msgstr ""
msgstr "停止寻求"
#: src/toolbars/ScrubbingToolBar.cpp:171
#, fuzzy
@ -13468,11 +13480,11 @@ msgstr "开始监视"
#: src/toolbars/ScrubbingToolBar.cpp:177
msgid "Hide Scrub Ruler"
msgstr ""
msgstr "隐藏磨砂标尺"
#: src/toolbars/ScrubbingToolBar.cpp:178
msgid "Show Scrub Ruler"
msgstr ""
msgstr "显示磨砂标尺"
#: src/toolbars/SelectionBar.cpp:88 src/toolbars/SelectionBar.cpp:303
msgid "Selection"
@ -13620,7 +13632,7 @@ msgstr "跟随播放"
#: src/tracks/ui/Scrubbing.cpp:243
msgid "See&k"
msgstr ""
msgstr "See&k"
#: src/tracks/ui/Scrubbing.cpp:243
#, fuzzy
@ -14198,27 +14210,27 @@ msgstr "点击并拖动以缩放工具栏"
#: src/widgets/Ruler.cpp:2089
msgid "Click & move to Scrub. Click & drag to Seek."
msgstr ""
msgstr "点击和移动到擦洗。点击拖动寻找。"
#: src/widgets/Ruler.cpp:2101
msgid "Move to Seek"
msgstr ""
msgstr "去寻找"
#: src/widgets/Ruler.cpp:2103
msgid "Move to Scrub"
msgstr ""
msgstr "移动擦洗"
#: src/widgets/Ruler.cpp:2110
msgid "Drag to Seek. Release to stop seeking."
msgstr ""
msgstr "拖动寻找。释放停止寻求。"
#: src/widgets/Ruler.cpp:2112
msgid "Drag to Seek. Release and move to Scrub."
msgstr ""
msgstr "拖动寻求。释放并移动到"
#: src/widgets/Ruler.cpp:2115
msgid "Move to Scrub. Drag to Seek."
msgstr ""
msgstr "移动磨砂拖动寻求。"
#: src/widgets/Ruler.cpp:2133
msgid "Timeline actions disabled during recording"
@ -14234,11 +14246,11 @@ msgstr "快速播放已启用"
#: src/widgets/Ruler.cpp:2840
msgid "Pinned Record/Play head"
msgstr ""
msgstr "固定录音/播放头"
#: src/widgets/Ruler.cpp:2841
msgid "Unpinned Record/Play head"
msgstr ""
msgstr "解除记录/播放头"
#: src/widgets/Ruler.cpp:2881
msgid "Disable Quick-Play"
@ -14282,7 +14294,7 @@ msgstr "解锁播放区域"
#: src/widgets/Ruler.cpp:2913
msgid "Disable Scrub Ruler"
msgstr ""
msgstr "禁用磨砂标尺"
#: src/widgets/Ruler.cpp:2915
#, fuzzy

View File

@ -1,141 +1,100 @@
;nyquist plug-in
;version 1
;version 4
;type process
;preview enabled
;categories "http://audacityteam.org/namespace#NoiseRemoval"
;name "Clip Fix..."
;action "Reconstructing clips..."
;author "Benjamin Schwartz"
;author "Benjamin Schwartz and Steve Daulton"
;copyright "Licensing confirmed under terms of the GNU General Public License version 2"
;; clipfix.ny by Benjamin Schwartz.
;; Licensing confirmed under terms of the GNU General Public License version 2:
;; http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
;; with kind agreement of Benjamin Schwartz, December 2011.
;; GUI updated by Steve Daulton July 2012
;;
;; For information about writing and modifying Nyquist plug-ins:
;; http://wiki.audacityteam.org/wiki/Nyquist_Plug-ins_Reference
;; Algorithm by Benjamin Schwartz
;; Clip Fix is a simple, stupid (but not blind) digital-clipping-corrector
;; The algorithm is fairly simple:
;; 1. Find all clipped regions
;; 2. Get the slope immediately on either side of the region
;; 3. Do a cubic spline interpolation.
;; 4. Go to next region
;control thresh "Threshold of Clipping (%)" real "" 95 0 100
;control threshold "Threshold of Clipping (%)" float "" 95 0 100
;control gain "Reduce amplitude to allow for restored peaks (dB)" float "" -9 -30 0
(setf largenumber 100000000) ;;Largest number of samples that can be imported
(setf blocksize 100000)
;;Clip Fix is a simple, stupid (but not blind) digital-clipping-corrector
;;The algorithm is fairly simple:
;;1. Find all clipped regions
;;2. Get the slope immediately on either side of the region
;;3. Do a cubic spline interpolation.
;;4. Go to next region
;;Coded from start (didn't know lisp (well, scheme, but not not lisp and certainly not
;;some XLISP 2.0 derivative)) to finish
;;(fully working, more or less) in one afternoon (and some evening).
;;Written by Benjamin Schwartz, MIT class of 2006, on May 25, 2004.
;;Explanatory text added by Gale Andrews, May 2008.
(defun declip (sin) ;;Central function
(let* ((threshold (* (peak sin largenumber) thresh 0.01))
(s2 (snd-copy sin))
(samplerate (snd-srate s2))
(s2length (snd-length s2 largenumber)))
(seqrep (i (1+ (/ s2length blocksize)))
(let ((l (min blocksize (- s2length (* i blocksize)))))
;;(print (list i t0 l samplerate))
(snd-from-array 0 samplerate
(workhorse
;;(let () (print (list s2 (type-of s2) l (type-of l)))
(snd-fetch-array s2 l l)
;;)
threshold))))
;;(setf r (snd-fetch-array (snd-copy s) (snd-length s largenumber) 1)) ;;Create a sound array
;;(snd-from-array (snd-t0 s) (snd-srate s) (workhorse r threshold))
))
(defun workhorse (r threshold)
(setf n (length r)) ;; Record its length
(setf exithigh ()) ;;Times when the wavefrom left the allowed region
(setf returnhigh ()) ;;Times when it returned to the allowed region
(setf drange 4)
(let ((i drange) (max (- n drange))) ;;Leave room at ends for derivative processing
(while (< i max)
(if (>= (aref r i) threshold)
(if (< (aref r (- i 1)) threshold)
(setq exithigh (cons (- i 1) exithigh))) ;;We just crossed the threshold up
(if (>= (aref r (- i 1)) threshold)
(setq returnhigh (cons i returnhigh)))) ;;We just crossed the threshold down
(setq i (1+ i))))
(setq exithigh (reverse exithigh)) ;;List comes out backwards
(setq returnhigh (reverse returnhigh))
(if (>= (aref r (1- drange)) threshold) ;;If the audio begins in a clipped region, ignore
(setq returnhigh (cdr returnhigh))) ;the extra return from threshold
(setf exitlow ()) ;; Same as above, but for the bottom threshold
(setf returnlow ())
(setf threshlow (* -1 threshold)) ;;Assumes your digital range is zero-centered
(setf threshold (/ threshold 100))
(setf gain (db-to-linear gain))
(setf buffersize 100000)
(setf slopelength 4) ; number of samples used to calculate the exit / re-entry slope
(let ((i drange) (max (- n drange)))
(while (< i max)
(if (<= (aref r i) threshlow)
(if (> (aref r (- i 1)) threshlow)
(setq exitlow (cons (- i 1) exitlow)))
(if (<= (aref r (- i 1)) threshlow)
(setq returnlow (cons i returnlow))))
(setq i (1+ i))))
(defun declip (sig thresh peak)
(let* ((threshold (* thresh peak))
(ln (truncate len))
(finalbufsize (rem ln buffersize)))
;; Calculate the number of buffers we can process.
;; if final buffer is not large enough for de-clipping we
;; will just add it on the end as is.
(if (>= finalbufsize slopelength)
(setf buffercount (1+ (/ ln buffersize)))
(setf buffercount (/ ln buffersize)))
;;; Make output sequence from processed buffers
(setf out
(seqrep (i buffercount)
(let* ((step (min buffersize (- ln (* i buffersize))))
(buffer (snd-fetch-array sig step step))
(processed (process buffer threshold step)))
(cue (mult gain
(snd-from-array 0 *sound-srate* processed))))))
;;; If there's unprocessed audio remaining, add it to the end
(if (and (> finalbufsize 0)(< finalbufsize slopelength))
(seq out (cue (getfinalblock sig finalbufsize gain)))
out)))
(setq exitlow (reverse exitlow))
(setq returnlow (reverse returnlow))
(if (<= (aref r (1- drange)) threshlow)
(setq returnlow (cdr returnlow)))
(defun getfinalblock (sig step gain)
(let ((block (snd-fetch-array sig step step)))
(mult gain (snd-from-array 0 *sound-srate* block))))
(while (and exithigh returnhigh) ;;If there are more clipped regions
(let* ((t1 (car exithigh)) ;;exit time
(t2 (car returnhigh)) ;;return time
(d1 (max 0 (/ (- (aref r t1) (aref r (- t1 (1- drange)))) (1- drange)))) ;;slope at exit
(d2 (min 0 (/ (- (aref r (+ t2 (1- drange))) (aref r t2)) (1- drange)))) ;;slope at return
(m (/ (+ d2 d1) (* (- t2 t1) (- t2 t1)))) ;;interpolation is by (t-t1)(t-t2)(mx+b)
(b (- (/ d2 (- t2 t1)) (* m t2))) ;;These values of m and b make the cubic seamless
(j (1+ t1))) ;; j is the index
(while (< j t2)
(setf (aref r j) (+ (aref r t1) (* (- j t1) (- j t2) (+ (* m j) b))))
(setf (aref r j) (+ (* (- t2 j) (/ (aref r t1) (- t2 t1))) (* (- j t1) (/ (aref r t2) (- t2 t1))) (* (- j t1) (- j t2) (+ (* m j) b))))
(setq j (1+ j))))
(setq exithigh (cdr exithigh))
(setq returnhigh (cdr returnhigh)))
(defun process (buffer threshold bufferlength)
;;; Find threshold crossings
(setf exit-list ()) ; list of times when waveform exceeds threshold
(setf return-list ()) ; list of times when waveform returns below threshold
;; Limitation of algorithm: the first and last 'slopelength' at ends of buffer are ignored
;; so that we have enough samples beyond the threshold crossing to calculate the slope.
(let ((last-sample (- bufferlength slopelength)))
(do ((i slopelength (1+ i)))
((>= i last-sample))
(if (>= (abs (aref buffer i)) threshold)
(when (< (abs (aref buffer (- i 1))) threshold) ; we just crossed threshold
(push (- i 1) exit-list))
(when (>= (abs (aref buffer (- i 1))) threshold) ; we just got back in range
(push i return-list)))))
;; Reverse lists back into chronological order.
;; This is faster than appending values in chronological order.
(setf exit-list (reverse exit-list))
(setf return-list (reverse return-list))
;; If the audio begins in a clipped region, discard the first return
(when (>= (abs (aref buffer (1- slopelength))) threshold)
(setq return-list (cdr return-list)))
;; Interpolate between each pair of exit / entry points
(let ((slopelen (1- slopelength)))
(mapc (lambda (t0 t1)
(interpolate buffer t0 t1 slopelen))
exit-list return-list))
buffer)
(while (and exitlow returnlow) ;;Same for bottom
(let* ((t1 (car exitlow))
(t2 (car returnlow))
(d1 (min 0 (/ (- (aref r t1) (aref r (- t1 (1- drange)))) (1- drange)))) ;;slope at exit
(d2 (max 0 (/ (- (aref r (+ t2 (1- drange))) (aref r t2)) (1- drange)))) ;;slope at return
(m (/ (+ d2 d1) (* (- t2 t1) (- t2 t1))))
(b (- (/ d2 (- t2 t1)) (* m t2)))
(a (/ (+ (aref r t1) (aref r t2)) 2))
(j (1+ t1)))
(while (< j t2)
(setf (aref r j) (+ (* (- t2 j) (/ (aref r t1) (- t2 t1))) (* (- j t1) (/ (aref r t2) (- t2 t1))) (* (- j t1) (- j t2) (+ (* m j) b))))
(setq j (1+ j))))
(setq exitlow (cdr exitlow))
(setq returnlow (cdr returnlow)))
r)
(defun interpolate (buffer t0 t1 dur)
"Cubic spline interpolation"
(let* ((d0 (/ (- (aref buffer t0) (aref buffer (- t0 dur))) dur)) ; slope at start
(d1 (/ (- (aref buffer (+ t1 dur)) (aref buffer t1)) dur)) ; slope at end
(m (/ (+ d1 d0) (* (- t1 t0) (- t1 t0))))
(b (- (/ d1 (- t1 t0)) (* m t1))))
(do ((j (1+ t0) (1+ j)))
((= j t1))
(setf (aref buffer j)
(+ (* (- t1 j) (/ (aref buffer t0) (- t1 t0)))
(* (- j t0) (/ (aref buffer t1) (- t1 t0)))
(* (- j t0) (- j t1) (+ (* m j) b)))))))
(if (arrayp s)
(dotimes (j (length s))
(setf (aref s j) (declip (aref s j))))
(setq s (declip s)))
s
;; (get '*selection* 'peak) introduced in Audacity 2.1.3
(multichan-expand #'declip *track* threshold (get '*selection* 'peak))

View File

@ -39,7 +39,7 @@ protected:
// Make this protected to prevent slicing copies
AudacityException( AudacityException&& ) {}
AudacityException( const AudacityException& ) = default;
AudacityException &operator = (AudacityException &&) {}
AudacityException &operator = (AudacityException &&) { return *this;}
AudacityException &operator = ( const AudacityException & ) PROHIBITED;
};

View File

@ -28,8 +28,8 @@
To highlight this deliniation, the file is divided into three parts
based on what thread context each function is intended to run in.
\par EXPERIMENTAL_MIDI_PLAYBACK
If EXPERIMENTAL_MIDI_PLAYBACK is defined, this class also manages
\par EXPERIMENTAL_MIDI_OUT
If EXPERIMENTAL_MIDI_OUT is defined, this class also manages
MIDI playback. The reason for putting MIDI here rather than in, say,
class MidiIO, is that there is no high-level synchronization and
transport architecture, so Audio and MIDI must be coupled in order
@ -3790,7 +3790,7 @@ void AudioIO::OutputEvent()
data1 = mNextEvent->get_pitch();
if (mNextIsNoteOn) {
data2 = mNextEvent->get_loud(); // get velocity
int offset = mNextEventTrack->GetGain();
int offset = mNextEventTrack->GetVelocity();
data2 += offset; // offset comes from per-track slider
// clip velocity to insure a legal note-on value
data2 = (data2 < 0 ? 1 : (data2 > 127 ? 127 : data2));
@ -3897,7 +3897,7 @@ void AudioIO::FillMidiBuffers()
hasSolo = true;
break;
}
int numMidiPlaybackTracks = gAudioIO->mMidiPlaybackTracks.size();
auto numMidiPlaybackTracks = gAudioIO->mMidiPlaybackTracks.size();
for(unsigned t = 0; t < numMidiPlaybackTracks; t++ )
if( gAudioIO->mMidiPlaybackTracks[t]->GetSolo() ) {
hasSolo = true;
@ -4370,7 +4370,7 @@ int audacityAudioCallback(const void *inputBuffer, void *outputBuffer,
if( gAudioIO->mPlaybackTracks[t]->GetSolo() )
numSolo++;
#ifdef EXPERIMENTAL_MIDI_OUT
int numMidiPlaybackTracks = gAudioIO->mMidiPlaybackTracks.size();
auto numMidiPlaybackTracks = gAudioIO->mMidiPlaybackTracks.size();
for( unsigned t = 0; t < numMidiPlaybackTracks; t++ )
if( gAudioIO->mMidiPlaybackTracks[t]->GetSolo() )
numSolo++;

View File

@ -135,7 +135,7 @@ void AutoRecoveryDialog::OnQuitAudacity(wxCommandEvent & WXUNUSED(event))
void AutoRecoveryDialog::OnRecoverNone(wxCommandEvent & WXUNUSED(event))
{
int ret = wxMessageBox(
_("Are you sure you want to discard all projects?\n\nChoosing \"Yes\" discards all projects immediately."),
_("Are you sure you want to discard all recoverable projects?\n\nChoosing \"Yes\" discards all recoverable projects immediately."),
_("Confirm Discard Projects"), wxICON_QUESTION | wxYES_NO | wxNO_DEFAULT, this);
if (ret == wxYES)

View File

@ -278,7 +278,7 @@ BEGIN_EVENT_TABLE(DependencyDialog, wxDialogWrapper)
EVT_LIST_ITEM_DESELECTED(FileListID, DependencyDialog::OnList)
EVT_BUTTON(CopySelectedFilesButtonID, DependencyDialog::OnCopySelectedFiles)
EVT_SIZE(DependencyDialog::OnSize)
EVT_BUTTON(wxID_NO, DependencyDialog::OnNo) // mIsSaving ? "Cancel Save" : "Save without Copying"
EVT_BUTTON(wxID_NO, DependencyDialog::OnNo) // mIsSaving ? "Cancel Save" : "Save Without Copying"
EVT_BUTTON(wxID_YES, DependencyDialog::OnYes) // "Copy All Files (Safer)"
EVT_BUTTON(wxID_CANCEL, DependencyDialog::OnCancel) // "Cancel Save"
END_EVENT_TABLE()
@ -349,7 +349,7 @@ void DependencyDialog::PopulateOrExchange(ShuttleGui& S)
{
if (mIsSaving) {
S.Id(wxID_CANCEL).AddButton(_("Cancel Save"));
S.Id(wxID_NO).AddButton(_("Save without Copying"));
S.Id(wxID_NO).AddButton(_("Save Without Copying"));
}
else
S.Id(wxID_NO).AddButton(_("Do Not Copy"));

View File

@ -198,7 +198,7 @@ EnvPoint *Envelope::AddPointAtEnd( double t, double val )
void Envelope::CopyFrom(const Envelope *e, double t0, double t1)
{
wxASSERT( t0 < t1 );
wxASSERT( t0 <= t1 );
mOffset = wxMax(t0, e->mOffset);
mTrackLen = wxMin(t1, e->mOffset + e->mTrackLen) - mOffset;

View File

@ -589,7 +589,7 @@ void LabelDialog::OnImport(wxCommandEvent & WXUNUSED(event))
// Ask user for a filename
wxString fileName =
FileSelector(_("Select a text file containing labels..."),
FileSelector(_("Select a text file containing labels"),
path, // Path
wxT(""), // Name
wxT(".txt"), // Extension

View File

@ -684,6 +684,17 @@ void AudacityProject::CreateMenusAndCommands()
c->AddSeparator();
c->AddSeparator();
c->BeginSubMenu(_("S&kip to"));
c->AddItem(wxT("SkipSelStart"), _("Selection Sta&rt"), FN(OnGoSelStart), wxT("Ctrl+["),
TimeSelectedFlag, TimeSelectedFlag);
c->AddItem(wxT("SkipSelEnd"), _("Selection En&d"), FN(OnGoSelEnd), wxT("Ctrl+]"),
TimeSelectedFlag, TimeSelectedFlag);
c->EndSubMenu();
c->AddSeparator();
c->AddCheck(wxT("ShowClipping"), _("&Show Clipping"), FN(OnShowClipping),
gPrefs->Read(wxT("/GUI/ShowClipping"), 0L), AlwaysEnabledFlag, AlwaysEnabledFlag);
@ -784,17 +795,19 @@ void AudacityProject::CreateMenusAndCommands()
AudioIONotBusyFlag | CanStopAudioStreamFlag);
/* i18n-hint: (verb)*/
c->AddItem(wxT("Record"), _("&Record"), FN(OnRecord), wxT("R"));
c->AddItem(wxT("TimerRecord"), _("&Timer Record..."), FN(OnTimerRecord), wxT("Shift+T"));
// The RecordBelow function is actually 'record-other', i.e. if normal record record beside,
// it records below, if normal record records below, it records beside.
// TODO: fix the naming, and also check we do 'the right thing' with other options like
// TimerRecord.
#ifdef EXPERIMENTAL_DA
c->AddItem(wxT("RecordBelow"), _("Record Below"), FN(OnRecordBelow), wxT("Shift+R"));
// The RecordBelow function is actually 'record-other', i.e. if normal record records beside,
// it records below, if normal record records below, it records beside.
// TODO: fix the naming, and also check we do 'the right thing' with other options like
// TimerRecord.
// PREFER_NEW_TRACKS is defined if we want the old behaviour of by default adding a new track on
// every new recording.
#ifndef PREFER_NEW_TRACKS
c->AddItem(wxT("RecordBelow"), _("Record New Track"), FN(OnRecordBelow), wxT("Shift+R"));
#else
c->AddItem(wxT("RecordBelow"), _("Record Beside"), FN(OnRecordBelow), wxT("Shift+R"));
#endif
c->AddItem(wxT("TimerRecord"), _("&Timer Record..."), FN(OnTimerRecord), wxT("Shift+T"));
// JKC: I decided to duplicate this between play and record, rather than put it
// at the top level. AddItem can now cope with simple duplicated items.
c->AddItem(wxT("Pause"), _("&Pause"), FN(OnPause), wxT("P"));
@ -803,18 +816,6 @@ void AudacityProject::CreateMenusAndCommands()
// Scrubbing sub-menu
GetScrubber().AddMenuItems();
c->AddSeparator();
c->BeginSubMenu(_("Skip to"));
c->AddItem(wxT("GoSelStart"), _("Selection Sta&rt"), FN(OnGoSelStart), wxT("Ctrl+["), TimeSelectedFlag, TimeSelectedFlag);
c->AddItem(wxT("GoSelEnd"), _("Selection En&d"), FN(OnGoSelEnd), wxT("Ctrl+]"), TimeSelectedFlag, TimeSelectedFlag);
c->AddItem(wxT("SkipStart"), _("Track Start"), FN(OnSkipStart), wxT("Home"),
AudioIONotBusyFlag, AudioIONotBusyFlag);
c->AddItem(wxT("SkipEnd"), _("Track E&nd"), FN(OnSkipEnd), wxT("End"),
WaveTracksExistFlag | AudioIONotBusyFlag,
WaveTracksExistFlag | AudioIONotBusyFlag);
c->EndSubMenu();
#ifndef EXPERIMENTAL_DA
// JKC: ANSWER-ME: How is this different to 'Skip To' and how is it useful?
c->BeginSubMenu(_("Cursor to"));
@ -825,6 +826,9 @@ void AudacityProject::CreateMenusAndCommands()
c->AddItem(wxT("CursTrackStart"), _("Track &Start"), FN(OnCursorTrackStart), wxT("J"));
c->AddItem(wxT("CursTrackEnd"), _("Track &End"), FN(OnCursorTrackEnd), wxT("K"));
c->AddItem(wxT("CursProjectStart"), _("&Project Start"), FN(OnSkipStart), wxT("Home"));
c->AddItem(wxT("CursProjectEnd"), _("Project E&nd"), FN(OnSkipEnd), wxT("End"));
c->EndSubMenu();
#endif
@ -4604,11 +4608,13 @@ bool AudacityProject::HandlePasteNothingSelected()
pNewTrack = mTrackFactory->NewWaveTrack(w->GetSampleFormat(), w->GetRate());
}
break;
#ifdef USE_MIDI
case Track::Note:
pNewTrack = mTrackFactory->NewNoteTrack();
break;
#endif // USE_MIDI
case Track::Note:
pNewTrack = mTrackFactory->NewNoteTrack();
break;
#endif // USE_MIDI
case Track::Label:
pNewTrack = mTrackFactory->NewLabelTrack();
break;
@ -5807,7 +5813,7 @@ void AudacityProject::OnImportLabels()
wxString path = gPrefs->Read(wxT("/DefaultOpenPath"),::wxGetCwd());
wxString fileName =
FileSelector(_("Select a text file containing labels..."),
FileSelector(_("Select a text file containing labels"),
path, // Path
wxT(""), // Name
wxT(".txt"), // Extension
@ -5852,7 +5858,7 @@ void AudacityProject::OnImportMIDI()
{
wxString path = gPrefs->Read(wxT("/DefaultOpenPath"),::wxGetCwd());
wxString fileName = FileSelector(_("Select a MIDI file..."),
wxString fileName = FileSelector(_("Select a MIDI file"),
path, // Path
wxT(""), // Name
wxT(""), // Extension
@ -5903,7 +5909,7 @@ void AudacityProject::OnImportRaw()
wxString path = gPrefs->Read(wxT("/DefaultOpenPath"),::wxGetCwd());
wxString fileName =
FileSelector(_("Select any uncompressed audio file..."),
FileSelector(_("Select any uncompressed audio file"),
path, // Path
wxT(""), // Name
wxT(""), // Extension
@ -6146,12 +6152,7 @@ void AudacityProject::HandleAlign(int index, bool moveSel)
while (t) {
// We only want Wave and Note tracks here.
#if defined(USE_MIDI)
if (t->GetSelected() && ((t->GetKind() == Track::Wave) ||
(t->GetKind() == Track::Note)))
#else
if (t->GetSelected() && (t->GetKind() == Track::Wave))
#endif
if (t->GetSelected() && dynamic_cast<const AudioTrack*>(t))
{
offset = t->GetOffset();
if (t->GetLinked()) { // Left channel of stereo track.
@ -6232,12 +6233,7 @@ void AudacityProject::HandleAlign(int index, bool moveSel)
while (t) {
// This shifts different tracks in different ways, so no sync-lock move.
// Only align Wave and Note tracks end to end.
#if defined(USE_MIDI)
if (t->GetSelected() && ((t->GetKind() == Track::Wave) ||
(t->GetKind() == Track::Note)))
#else
if (t->GetSelected() && (t->GetKind() == Track::Wave))
#endif
if (t->GetSelected() && dynamic_cast<const AudioTrack*>(t))
{
t->SetOffset(newPos); // Move the track
@ -6523,7 +6519,7 @@ void AudacityProject::OnScoreAlign()
if (alignedNoteTrack->GetSequence() == NULL) {
holder = alignedNoteTrack->Duplicate();
alignedNoteTrack = static_cast<NoteTrack*>(holder.get());
assert(alignedNoteTrack->GetSequence());
wxASSERT(alignedNoteTrack->GetSequence());
}
// Remove offset from NoteTrack because audio is
// mixed starting at zero and incorporating clip offsets.
@ -6893,8 +6889,9 @@ void AudacityProject::OnRemoveTracks()
while (t) {
if (t->GetSelected()) {
if (mMixerBoard && (t->GetKind() == Track::Wave))
mMixerBoard->RemoveTrackCluster((WaveTrack*)t);
auto playable = dynamic_cast<PlayableTrack*>(t);
if (mMixerBoard && playable)
mMixerBoard->RemoveTrackCluster(playable);
if (!f)
f = l; // Capture the track preceeding the first removed track
t = iter.RemoveCurrent();
@ -7091,8 +7088,9 @@ void AudacityProject::OnMuteAllTracks()
while (t)
{
if (t->GetKind() == Track::Wave)
t->SetMute(true);
auto pt = dynamic_cast<PlayableTrack *>(t);
if (pt)
pt->SetMute(true);
t = iter.Next();
}
@ -7110,7 +7108,9 @@ void AudacityProject::OnUnMuteAllTracks()
while (t)
{
t->SetMute(false);
auto pt = dynamic_cast<PlayableTrack *>(t);
if (pt)
pt->SetMute(false);
t = iter.Next();
}

View File

@ -255,7 +255,7 @@ Mixer::Mixer(const WaveTrackConstArray &inputTracks,
, mQueueMaxLen{ 65536 }
, mSampleQueue{ mNumInputTracks, mQueueMaxLen }
, mNumChannels{ static_cast<size_t>(numOutChannels) }
, mNumChannels{ numOutChannels }
, mGains{ mNumChannels }
, mMayThrow{ mayThrow }

View File

@ -23,9 +23,9 @@
#include "AColor.h"
#include "AudioIO.h"
#ifdef EXPERIMENTAL_MIDI_OUT
#include "NoteTrack.h"
#endif
#include "NoteTrack.h"
#include "Project.h"
#include "TrackPanel.h" // for EVT_TRACK_PANEL_TIMER
#include "UndoManager.h"
@ -155,30 +155,17 @@ END_EVENT_TABLE()
MixerTrackCluster::MixerTrackCluster(wxWindow* parent,
MixerBoard* grandParent, AudacityProject* project,
WaveTrack* pLeftTrack, WaveTrack* pRightTrack /*= NULL*/,
PlayableTrack* pTrack,
const wxPoint& pos /*= wxDefaultPosition*/,
const wxSize& size /*= wxDefaultSize*/)
: wxPanelWrapper(parent, -1, pos, size)
, mTrack{ pTrack }
{
mMixerBoard = grandParent;
mProject = project;
#ifdef EXPERIMENTAL_MIDI_OUT
if (pLeftTrack->GetKind() == Track::Note) {
mLeftTrack = NULL;
mNoteTrack = (NoteTrack*) pLeftTrack;
mTrack = pLeftTrack;
} else {
wxASSERT(pLeftTrack->GetKind() == Track::Wave);
mTrack = mLeftTrack = pLeftTrack;
mNoteTrack = NULL;
}
#else
wxASSERT(pLeftTrack->GetKind() == Track::Wave);
mLeftTrack = pLeftTrack;
#endif
mRightTrack = pRightTrack;
wxASSERT( pTrack );
SetName(mLeftTrack->GetName());
SetName(mTrack->GetName());
this->SetBackgroundColour(wxSystemSettings::GetColour(wxSYS_COLOUR_3DFACE));
@ -191,13 +178,8 @@ MixerTrackCluster::MixerTrackCluster(wxWindow* parent,
wxPoint ctrlPos(kDoubleInset, kDoubleInset);
wxSize ctrlSize(size.GetWidth() - kQuadrupleInset, TRACK_NAME_HEIGHT);
mStaticText_TrackName =
#ifdef EXPERIMENTAL_MIDI_OUT
safenew wxStaticText(this, -1, mTrack->GetName(), ctrlPos, ctrlSize,
wxALIGN_CENTRE | wxST_NO_AUTORESIZE | wxSUNKEN_BORDER);
#else
safenew wxStaticText(this, -1, mLeftTrack->GetName(), ctrlPos, ctrlSize,
wxALIGN_CENTRE | 0x0001 | wxBORDER_SUNKEN);
#endif
//v Useful when different tracks are different colors, but not now.
// mStaticText_TrackName->SetBackgroundColour(this->GetTrackColor());
@ -208,8 +190,9 @@ MixerTrackCluster::MixerTrackCluster(wxWindow* parent,
const int nGainSliderHeight =
size.GetHeight() - ctrlPos.y - kQuadrupleInset;
ctrlSize.Set(kLeftSideStackWidth - kQuadrupleInset, nGainSliderHeight);
#ifdef EXPERIMENTAL_MIDI_OUT
if (mNoteTrack) {
#ifdef USE_MIDI
if (GetNote()) {
mSlider_Gain =
safenew MixerTrackSlider(
this, ID_SLIDER_GAIN,
@ -217,15 +200,17 @@ MixerTrackCluster::MixerTrackCluster(wxWindow* parent,
_("Velocity"),
ctrlPos, ctrlSize, VEL_SLIDER, true,
true, 0.0, wxVERTICAL);
} else
}
else
#endif
mSlider_Gain =
safenew MixerTrackSlider(
this, ID_SLIDER_GAIN,
/* i18n-hint: title of the Gain slider, used to adjust the volume */
_("Gain"),
ctrlPos, ctrlSize, DB_SLIDER, true,
true, 0.0, wxVERTICAL);
mSlider_Gain =
safenew MixerTrackSlider(
this, ID_SLIDER_GAIN,
/* i18n-hint: title of the Gain slider, used to adjust the volume */
_("Gain"),
ctrlPos, ctrlSize, DB_SLIDER, true,
true, 0.0, wxVERTICAL);
mSlider_Gain->SetName(_("Gain"));
this->UpdateGain();
@ -236,11 +221,7 @@ MixerTrackCluster::MixerTrackCluster(wxWindow* parent,
// musical instrument image
ctrlPos.x += kLeftSideStackWidth + kInset; // + kInset to center it in right side stack
ctrlSize.Set(MUSICAL_INSTRUMENT_HEIGHT_AND_WIDTH, MUSICAL_INSTRUMENT_HEIGHT_AND_WIDTH);
#ifdef EXPERIMENTAL_MIDI_OUT
wxBitmap* bitmap = mMixerBoard->GetMusicalInstrumentBitmap(mTrack->GetName());
#else
wxBitmap* bitmap = mMixerBoard->GetMusicalInstrumentBitmap(mLeftTrack);
#endif
wxBitmap* bitmap = mMixerBoard->GetMusicalInstrumentBitmap(mTrack);
wxASSERT(bitmap);
mBitmapButton_MusicalInstrument =
safenew wxBitmapButton(this, ID_BITMAPBUTTON_MUSICAL_INSTRUMENT, *bitmap,
@ -306,34 +287,24 @@ MixerTrackCluster::MixerTrackCluster(wxWindow* parent,
(PAN_HEIGHT + kDoubleInset) -
(MUTE_SOLO_HEIGHT + (bSoloNone ? 0 : MUTE_SOLO_HEIGHT) + kDoubleInset);
ctrlSize.Set(kRightSideStackWidth, nMeterHeight);
#ifdef EXPERIMENTAL_MIDI_OUT
if (mLeftTrack) {
#endif
mMeter =
safenew Meter(GetActiveProject(), // AudacityProject* project,
this, -1, // wxWindow* parent, wxWindowID id,
false, // bool isInput
ctrlPos, ctrlSize, // const wxPoint& pos = wxDefaultPosition, const wxSize& size = wxDefaultSize,
Meter::MixerTrackCluster); // Style style = HorizontalStereo,
mMeter->SetName(_("Signal Level Meter"));
#ifdef EXPERIMENTAL_MIDI_OUT
} else {
mMeter = NULL;
mMeter = NULL;
if (GetWave()) {
mMeter =
safenew Meter(GetActiveProject(), // AudacityProject* project,
this, -1, // wxWindow* parent, wxWindowID id,
false, // bool isInput
ctrlPos, ctrlSize, // const wxPoint& pos = wxDefaultPosition, const wxSize& size = wxDefaultSize,
Meter::MixerTrackCluster); // Style style = HorizontalStereo,
mMeter->SetName(_("Signal Level Meter"));
}
#endif
#if wxUSE_TOOLTIPS
#ifdef EXPERIMENTAL_MIDI_OUT
mStaticText_TrackName->SetToolTip(mTrack->GetName());
#else
mStaticText_TrackName->SetToolTip(mLeftTrack->GetName());
#endif
mToggleButton_Mute->SetToolTip(_("Mute"));
mToggleButton_Solo->SetToolTip(_("Solo"));
#ifdef EXPERIMENTAL_MIDI_OUT
if (mLeftTrack)
#endif
mMeter->SetToolTip(_("Signal Level Meter"));
if (GetWave())
mMeter->SetToolTip(_("Signal Level Meter"));
#endif // wxUSE_TOOLTIPS
#ifdef __WXMAC__
@ -344,9 +315,31 @@ MixerTrackCluster::MixerTrackCluster(wxWindow* parent,
#endif
}
WaveTrack *MixerTrackCluster::GetWave() const
{
return dynamic_cast< WaveTrack * >( mTrack );
}
WaveTrack *MixerTrackCluster::GetRight() const
{
auto left = GetWave();
if (left)
return static_cast<WaveTrack*>(left->GetLink());
else
return nullptr;
}
#ifdef USE_MIDI
NoteTrack *MixerTrackCluster::GetNote() const
{
return dynamic_cast< NoteTrack * >( mTrack );
}
#endif
void MixerTrackCluster::UpdatePrefs()
{
mMeter->UpdatePrefs(); // in case meter range has changed
if (mMeter)
mMeter->UpdatePrefs(); // in case meter range has changed
HandleResize(); // in case prefs "/GUI/Solo" changed
}
@ -382,30 +375,24 @@ void MixerTrackCluster::HandleResize() // For wxSizeEvents, update gain slider a
TRACK_NAME_HEIGHT + kDoubleInset +
nRequiredHeightAboveMeter;
const int nMeterHeight = nGainSliderHeight - nRequiredHeightAboveMeter;
#ifdef EXPERIMENTAL_MIDI_OUT
if (mMeter)
#endif
mMeter->SetSize(-1, nMeterY, -1, nMeterHeight);
mMeter->SetSize(-1, nMeterY, -1, nMeterHeight);
}
void MixerTrackCluster::HandleSliderGain(const bool bWantPushState /*= false*/)
{
float fValue = mSlider_Gain->Get();
if (mLeftTrack)
mLeftTrack->SetGain(fValue);
if (GetWave())
GetWave()->SetGain(fValue);
#ifdef EXPERIMENTAL_MIDI_OUT
else
mNoteTrack->SetGain(fValue);
GetNote()->SetVelocity(fValue);
#endif
if (mRightTrack)
mRightTrack->SetGain(fValue);
if (GetRight())
GetRight()->SetGain(fValue);
// Update the TrackPanel correspondingly.
#ifdef EXPERIMENTAL_MIDI_OUT
mProject->RefreshTPTrack(mTrack);
#else
mProject->RefreshTPTrack(mLeftTrack);
#endif
if (bWantPushState)
mProject->TP_PushState(_("Moved gain slider"), _("Gain"), UndoPush::CONSOLIDATE );
}
@ -413,17 +400,13 @@ void MixerTrackCluster::HandleSliderGain(const bool bWantPushState /*= false*/)
void MixerTrackCluster::HandleSliderPan(const bool bWantPushState /*= false*/)
{
float fValue = mSlider_Pan->Get();
if (mLeftTrack) // test in case track is a NoteTrack
mLeftTrack->SetPan(fValue);
if (mRightTrack)
mRightTrack->SetPan(fValue);
if (GetWave()) // test in case track is a NoteTrack
GetWave()->SetPan(fValue);
if (GetRight())
GetRight()->SetPan(fValue);
// Update the TrackPanel correspondingly.
#ifdef EXPERIMENTAL_MIDI_OUT
mProject->RefreshTPTrack(mTrack);
#else
mProject->RefreshTPTrack(mLeftTrack);
#endif
if (bWantPushState)
mProject->TP_PushState(_("Moved pan slider"), _("Pan"), UndoPush::CONSOLIDATE );
@ -431,10 +414,8 @@ void MixerTrackCluster::HandleSliderPan(const bool bWantPushState /*= false*/)
void MixerTrackCluster::ResetMeter(const bool bResetClipping)
{
#ifdef EXPERIMENTAL_MIDI_OUT
if (mMeter)
#endif
mMeter->Reset(mLeftTrack->GetRate(), bResetClipping);
mMeter->Reset(GetWave()->GetRate(), bResetClipping);
}
@ -450,33 +431,20 @@ void MixerTrackCluster::UpdateForStateChange()
void MixerTrackCluster::UpdateName()
{
#ifdef EXPERIMENTAL_MIDI_OUT
const wxString newName = mTrack->GetName();
#else
const wxString newName = mLeftTrack->GetName();
#endif
SetName(newName);
mStaticText_TrackName->SetLabel(newName);
#if wxUSE_TOOLTIPS
mStaticText_TrackName->SetToolTip(newName);
#endif
mBitmapButton_MusicalInstrument->SetBitmapLabel(
#ifdef EXPERIMENTAL_MIDI_OUT
*(mMixerBoard->GetMusicalInstrumentBitmap(newName)));
#else
*(mMixerBoard->GetMusicalInstrumentBitmap(mLeftTrack)));
#endif
*(mMixerBoard->GetMusicalInstrumentBitmap(mTrack)));
}
void MixerTrackCluster::UpdateMute()
{
#ifdef EXPERIMENTAL_MIDI_OUT
mToggleButton_Mute->SetAlternateIdx(mTrack->GetSolo() ? 1 : 0);
if (mTrack->GetMute())
#else
mToggleButton_Mute->SetAlternateIdx(mLeftTrack->GetSolo() ? 1 : 0);
if (mLeftTrack->GetMute())
#endif
mToggleButton_Mute->PushDown();
else
mToggleButton_Mute->PopUp();
@ -484,11 +452,7 @@ void MixerTrackCluster::UpdateMute()
void MixerTrackCluster::UpdateSolo()
{
#ifdef EXPERIMENTAL_MIDI_OUT
bool bIsSolo = mTrack->GetSolo();
#else
bool bIsSolo = mLeftTrack->GetSolo();
#endif
if (bIsSolo)
mToggleButton_Solo->PushDown();
else
@ -499,55 +463,36 @@ void MixerTrackCluster::UpdateSolo()
void MixerTrackCluster::UpdatePan()
{
#ifdef EXPERIMENTAL_MIDI_OUT
if (mNoteTrack) {
if (!GetWave()) {
mSlider_Pan->Hide();
return;
}
#endif
mSlider_Pan->Set(mLeftTrack->GetPan());
mSlider_Pan->Set(GetWave()->GetPan());
}
void MixerTrackCluster::UpdateGain()
{
#ifdef EXPERIMENTAL_MIDI_OUT
if (mNoteTrack) {
if (!GetWave()) {
mSlider_Gain->SetStyle(VEL_SLIDER);
mSlider_Gain->Set(mNoteTrack->GetGain());
mSlider_Gain->Set(GetNote()->GetVelocity());
return;
}
mSlider_Gain->SetStyle(DB_SLIDER);
#endif
mSlider_Gain->Set(mLeftTrack->GetGain());
mSlider_Gain->Set(GetWave()->GetGain());
}
void MixerTrackCluster::UpdateMeter(const double t0, const double t1)
{
#ifdef EXPERIMENTAL_MIDI_OUT
// NoteTracks do not (currently) register on meters. It would probably be
// a good idea to display 16 channel "active" lights rather than a meter
if (!mLeftTrack)
if (!GetWave())
return;
#else
wxASSERT(mLeftTrack && (mLeftTrack->GetKind() == Track::Wave));
#endif
//vvv Vaughan, 2010-11-27:
// NOTE TO ROGER DANNENBERG:
// I undid the mTrack hack in this conditional, as the rest of the method still assumed it's a wavetrack
// so dereferencing mLeftTrack would have gotten a NULL pointer fault.
// I really think MixerTrackCluster should be factored for NoteTracks.
// REPLY: I think bSuccess prevents dereferencing mLeftTrack, but I will
// check. We should talk about whether it's better to factor
// MixerTrackCluster or more fully hide track types from MixerTrackCluster.
// For now, out change plan produced the following:
// Vaughan, 2011=10-15: There's no bSuccess here, so I don't know what you mean.
// But this change is consistent with the others for EXPERIMENTAL_MIDI_OUT, so I accept it.
if ((t0 < 0.0) || (t1 < 0.0) || (t0 >= t1) || // bad time value or nothing to show
#ifdef EXPERIMENTAL_MIDI_OUT
((mMixerBoard->HasSolo() || mTrack->GetMute()) && !mTrack->GetSolo())
#else
((mMixerBoard->HasSolo() || mLeftTrack->GetMute()) && !mLeftTrack->GetSolo())
#endif
)
{
//v Vaughan, 2011-02-25: Moved the update back to TrackPanel::OnTimer() as it helps with
@ -577,7 +522,7 @@ void MixerTrackCluster::UpdateMeter(const double t0, const double t1)
//Floats rmsRight{kFramesPerBuffer};
//
//#ifdef EXPERIMENTAL_MIDI_OUT
// bool bSuccess = (mLeftTrack != NULL);
// bool bSuccess = (GetWave() != nullptr);
//#else
// bool bSuccess = true;
//#endif
@ -589,8 +534,8 @@ void MixerTrackCluster::UpdateMeter(const double t0, const double t1)
//while (bSuccess && (i < kFramesPerBuffer))
//{
// bSuccess &=
// mLeftTrack->GetMinMax(&min, &(maxLeft[i]), dFrameT0, dFrameT1) &&
// mLeftTrack->GetRMS(&(rmsLeft[i]), dFrameT0, dFrameT1);
// mTrack->GetMinMax(&min, &(maxLeft[i]), dFrameT0, dFrameT1) &&
// mTrack->GetRMS(&(rmsLeft[i]), dFrameT0, dFrameT1);
// if (bSuccess && mRightTrack)
// bSuccess &=
// mRightTrack->GetMinMax(&min, &(maxRight[i]), dFrameT0, dFrameT1) &&
@ -613,7 +558,7 @@ void MixerTrackCluster::UpdateMeter(const double t0, const double t1)
//{
// for (i = 0; i < kFramesPerBuffer; i++)
// {
// float gain = mLeftTrack->GetChannelGain(0);
// float gain = mTrack->GetChannelGain(0);
// maxLeft[i] *= gain;
// rmsLeft[i] *= gain;
// if (mRightTrack)
@ -621,17 +566,18 @@ void MixerTrackCluster::UpdateMeter(const double t0, const double t1)
// maxRight[i] *= gain;
// rmsRight[i] *= gain;
// }
// mMeter->UpdateDisplay(
// if ( mMeter ) mMeter->UpdateDisplay(
// 2, // If mono, show left track values in both meters, as in MeterToolBar, rather than kNumChannels.
// kFramesPerBuffer,
// maxLeft, rmsLeft,
// maxRight, rmsRight,
// mLeftTrack->TimeToLongSamples(t1 - t0));
// mTrack->TimeToLongSamples(t1 - t0));
//}
//
auto startSample = (sampleCount)((mLeftTrack->GetRate() * t0) + 0.5);
auto scnFrames = (sampleCount)((mLeftTrack->GetRate() * (t1 - t0)) + 0.5);
const auto pTrack = GetWave();
auto startSample = (sampleCount)((pTrack->GetRate() * t0) + 0.5);
auto scnFrames = (sampleCount)((pTrack->GetRate() * (t1 - t0)) + 0.5);
// Expect that the difference of t1 and t0 is the part of a track played
// in about 1/20 second (ticks of TrackPanel timer), so this won't overflow
@ -640,7 +586,7 @@ void MixerTrackCluster::UpdateMeter(const double t0, const double t1)
Floats tempFloatsArray{ nFrames };
decltype(tempFloatsArray) meterFloatsArray;
// Don't throw on read error in this drawing update routine
bool bSuccess = mLeftTrack->Get((samplePtr)tempFloatsArray.get(),
bool bSuccess = pTrack->Get((samplePtr)tempFloatsArray.get(),
floatSample, startSample, nFrames, fillZero, false);
if (bSuccess)
{
@ -653,9 +599,9 @@ void MixerTrackCluster::UpdateMeter(const double t0, const double t1)
for (int index = 0; index < nFrames; index++)
meterFloatsArray[2 * index] = tempFloatsArray[index];
if (mRightTrack)
if (GetRight())
// Again, don't throw
bSuccess = mRightTrack->Get((samplePtr)tempFloatsArray.get(),
bSuccess = GetRight()->Get((samplePtr)tempFloatsArray.get(),
floatSample, startSample, nFrames, fillZero, false);
if (bSuccess)
@ -669,14 +615,14 @@ void MixerTrackCluster::UpdateMeter(const double t0, const double t1)
if (bSuccess)
{
//vvv Need to apply envelope, too? See Mixer::MixSameRate.
float gain = mLeftTrack->GetChannelGain(0);
float gain = pTrack->GetChannelGain(0);
if (gain < 1.0)
for (int index = 0; index < nFrames; index++)
meterFloatsArray[2 * index] *= gain;
if (mRightTrack)
gain = mRightTrack->GetChannelGain(1);
if (GetRight())
gain = GetRight()->GetChannelGain(1);
else
gain = mLeftTrack->GetChannelGain(1);
gain = pTrack->GetChannelGain(1);
if (gain < 1.0)
for (int index = 0; index < nFrames; index++)
meterFloatsArray[(2 * index) + 1] *= gain;
@ -705,13 +651,7 @@ wxColour MixerTrackCluster::GetTrackColor()
void MixerTrackCluster::HandleSelect(bool bShiftDown, bool bControlDown)
{
#ifdef EXPERIMENTAL_MIDI_OUT
Track *pTrack = mTrack;
#else
Track *pTrack = mLeftTrack;
#endif
mProject->GetTrackPanel()->HandleListSelection(pTrack, bShiftDown, bControlDown);
mProject->GetTrackPanel()->HandleListSelection(mTrack, bShiftDown, bControlDown);
}
void MixerTrackCluster::OnMouseEvent(wxMouseEvent& event)
@ -735,11 +675,7 @@ void MixerTrackCluster::OnPaint(wxPaintEvent & WXUNUSED(event))
wxSize clusterSize = this->GetSize();
wxRect bev(0, 0, clusterSize.GetWidth() - 1, clusterSize.GetHeight() - 1);
#ifdef EXPERIMENTAL_MIDI_OUT
auto selected = mTrack->GetSelected();
#else
auto selected = mLeftTrack->GetSelected();
#endif
for (unsigned int i = 0; i < 4; i++) // 4 gives a big bevel, but there were complaints about visibility otherwise.
{
@ -782,13 +718,8 @@ void MixerTrackCluster::OnSlider_Pan(wxCommandEvent& WXUNUSED(event))
void MixerTrackCluster::OnButton_Mute(wxCommandEvent& WXUNUSED(event))
{
#ifdef EXPERIMENTAL_MIDI_OUT
mProject->HandleTrackMute(mTrack, mToggleButton_Mute->WasShiftDown());
mToggleButton_Mute->SetAlternateIdx(mTrack->GetSolo() ? 1 : 0);
#else
mProject->HandleTrackMute(mLeftTrack, mToggleButton_Mute->WasShiftDown());
mToggleButton_Mute->SetAlternateIdx(mLeftTrack->GetSolo() ? 1 : 0);
#endif
// Update the TrackPanel correspondingly.
if (mProject->IsSoloSimple())
@ -799,22 +730,13 @@ void MixerTrackCluster::OnButton_Mute(wxCommandEvent& WXUNUSED(event))
}
else
// Update only the changed track.
#ifdef EXPERIMENTAL_MIDI_OUT
mProject->RefreshTPTrack(mTrack);
#else
mProject->RefreshTPTrack(mLeftTrack);
#endif
}
void MixerTrackCluster::OnButton_Solo(wxCommandEvent& WXUNUSED(event))
{
#ifdef EXPERIMENTAL_MIDI_OUT
mProject->HandleTrackSolo(mTrack, mToggleButton_Solo->WasShiftDown());
bool bIsSolo = mTrack->GetSolo();
#else
mProject->HandleTrackSolo(mLeftTrack, mToggleButton_Solo->WasShiftDown());
bool bIsSolo = mLeftTrack->GetSolo();
#endif
mToggleButton_Mute->SetAlternateIdx(bIsSolo ? 1 : 0);
// Update the TrackPanel correspondingly.
@ -827,11 +749,7 @@ void MixerTrackCluster::OnButton_Solo(wxCommandEvent& WXUNUSED(event))
}
else
// Update only the changed track.
#ifdef EXPERIMENTAL_MIDI_OUT
mProject->RefreshTPTrack(mTrack);
#else
mProject->RefreshTPTrack(mLeftTrack);
#endif
}
@ -1006,22 +924,18 @@ void MixerBoard::UpdateTrackClusters()
this->CreateMuteSoloImages();
const int nClusterHeight = mScrolledWindow->GetClientSize().GetHeight() - kDoubleInset;
const size_t nClusterCount = mMixerTrackClusters.GetCount();
size_t nClusterCount = mMixerTrackClusters.GetCount();
unsigned int nClusterIndex = 0;
TrackListIterator iterTracks(mTracks);
MixerTrackCluster* pMixerTrackCluster = NULL;
Track* pLeftTrack;
Track* pTrack;
Track* pRightTrack;
pLeftTrack = iterTracks.First();
while (pLeftTrack) {
pRightTrack = pLeftTrack->GetLinked() ? iterTracks.Next() : NULL;
pTrack = iterTracks.First();
while (pTrack) {
pRightTrack = pTrack->GetLinked() ? iterTracks.Next() : NULL;
if (pLeftTrack->GetKind() == Track::Wave
#ifdef EXPERIMENTAL_MIDI_OUT
|| pLeftTrack->GetKind() == Track::Note
#endif
)
if (auto pPlayableTrack = dynamic_cast<PlayableTrack*>(pTrack))
{
if (nClusterIndex < nClusterCount)
{
@ -1029,20 +943,8 @@ void MixerBoard::UpdateTrackClusters()
// Track clusters are maintained in the same order as the WaveTracks.
// Track pointers can change for the "same" track for different states
// on the undo stack, so update the pointers and display name.
#ifdef EXPERIMENTAL_MIDI_OUT
if (pLeftTrack->GetKind() == Track::Note) {
mMixerTrackClusters[nClusterIndex]->mNoteTrack = (NoteTrack*)pLeftTrack;
mMixerTrackClusters[nClusterIndex]->mLeftTrack = NULL;
} else {
mMixerTrackClusters[nClusterIndex]->mNoteTrack = NULL;
mMixerTrackClusters[nClusterIndex]->mLeftTrack = (WaveTrack*)pLeftTrack;
}
#else
mMixerTrackClusters[nClusterIndex]->mLeftTrack = (WaveTrack*)pLeftTrack;
#endif
mMixerTrackClusters[nClusterIndex]->mTrack = pPlayableTrack;
// Assume linked track is wave or null
mMixerTrackClusters[nClusterIndex]->mRightTrack =
static_cast<WaveTrack*>(pRightTrack);
mMixerTrackClusters[nClusterIndex]->UpdateForStateChange();
}
else
@ -1057,16 +959,14 @@ void MixerBoard::UpdateTrackClusters()
wxSize clusterSize(kMixerTrackClusterWidth, nClusterHeight);
pMixerTrackCluster =
safenew MixerTrackCluster(mScrolledWindow, this, mProject,
static_cast<WaveTrack*>(pLeftTrack),
// Assume linked track is wave or null
static_cast<WaveTrack*>(pRightTrack),
pPlayableTrack,
clusterPos, clusterSize);
if (pMixerTrackCluster)
mMixerTrackClusters.Add(pMixerTrackCluster);
}
nClusterIndex++;
}
pLeftTrack = iterTracks.Next();
pTrack = iterTracks.Next();
}
if (pMixerTrackCluster)
@ -1075,19 +975,14 @@ void MixerBoard::UpdateTrackClusters()
this->UpdateWidth();
this->ResizeTrackClusters();
}
else if (nClusterIndex < nClusterCount)
else while (nClusterIndex < nClusterCount)
{
// We've got too many clusters.
// This can happen only on things like Undo New Audio Track or Undo Import
// that don't call RemoveTrackCluster explicitly.
// We've already updated the track pointers for the clusters to the left, so just remove all the rest.
// Keep nClusterIndex constant and successively DELETE from left to right.
for (unsigned int nCounter = nClusterIndex; nCounter < nClusterCount; nCounter++)
#ifdef EXPERIMENTAL_MIDI_OUT
this->RemoveTrackCluster(mMixerTrackClusters[nClusterIndex]->mTrack);
#else
this->RemoveTrackCluster(mMixerTrackClusters[nClusterIndex]->mLeftTrack);
#endif
// Successively DELETE from right to left.
RemoveTrackCluster(--nClusterCount);
}
}
@ -1100,13 +995,8 @@ int MixerBoard::GetTrackClustersWidth()
kDoubleInset; // plus final right margin
}
#ifdef EXPERIMENTAL_MIDI_OUT
void MixerBoard::MoveTrackCluster(const Track* pTrack,
void MixerBoard::MoveTrackCluster(const PlayableTrack* pTrack,
bool bUp) // Up in TrackPanel is left in MixerBoard.
#else
void MixerBoard::MoveTrackCluster(const WaveTrack* pTrack,
bool bUp) // Up in TrackPanel is left in MixerBoard.
#endif
{
MixerTrackCluster* pMixerTrackCluster;
int nIndex = FindMixerTrackCluster(pTrack, &pMixerTrackCluster);
@ -1140,18 +1030,21 @@ void MixerBoard::MoveTrackCluster(const WaveTrack* pTrack,
}
}
#ifdef EXPERIMENTAL_MIDI_OUT
void MixerBoard::RemoveTrackCluster(const Track* pTrack)
#else
void MixerBoard::RemoveTrackCluster(const WaveTrack* pTrack)
#endif
void MixerBoard::RemoveTrackCluster(const PlayableTrack* pTrack)
{
// Find and destroy.
MixerTrackCluster* pMixerTrackCluster;
int nIndex = this->FindMixerTrackCluster(pTrack, &pMixerTrackCluster);
if (pMixerTrackCluster == NULL)
return; // Couldn't find it.
RemoveTrackCluster(nIndex);
}
void MixerBoard::RemoveTrackCluster(size_t nIndex)
{
auto pMixerTrackCluster = mMixerTrackClusters[nIndex];
mMixerTrackClusters.RemoveAt(nIndex);
pMixerTrackCluster->Destroy(); // DELETE is unsafe on wxWindow.
@ -1170,32 +1063,17 @@ void MixerBoard::RemoveTrackCluster(const WaveTrack* pTrack)
}
this->UpdateWidth();
#ifdef EXPERIMENTAL_MIDI_OUT
// Sanity check: if there is still a MixerTrackCluster with pTrack, then
// we deleted the first but should have deleted the last:
FindMixerTrackCluster(pTrack, &pMixerTrackCluster);
assert(pMixerTrackCluster == NULL);
#endif
}
#ifdef EXPERIMENTAL_MIDI_OUT
wxBitmap* MixerBoard::GetMusicalInstrumentBitmap(const wxString & name)
#else
wxBitmap* MixerBoard::GetMusicalInstrumentBitmap(const WaveTrack* pLeftTrack)
#endif
wxBitmap* MixerBoard::GetMusicalInstrumentBitmap(const Track* pTrack)
{
if (mMusicalInstruments.empty())
return NULL;
// random choice: return mMusicalInstruments[(int)pLeftTrack % mMusicalInstruments.GetCount()].mBitmap;
// random choice: return mMusicalInstruments[(int)pTrack % mMusicalInstruments.GetCount()].mBitmap;
#ifdef EXPERIMENTAL_MIDI_OUT
const wxString strTrackName(wxString{ name }.MakeLower());
#else
const wxString strTrackName(pLeftTrack->GetName().MakeLower());
#endif
const wxString strTrackName(pTrack->GetName().MakeLower());
size_t nBestItemIndex = 0;
unsigned int nBestScore = 0;
unsigned int nInstrIndex = 0;
@ -1236,17 +1114,15 @@ bool MixerBoard::HasSolo()
{
TrackListIterator iterTracks(mTracks);
Track* pTrack;
for (pTrack = iterTracks.First(); pTrack; pTrack = iterTracks.Next())
if (pTrack->GetSolo())
for (pTrack = iterTracks.First(); pTrack; pTrack = iterTracks.Next()) {
auto pPlayable = dynamic_cast<PlayableTrack *>( pTrack );
if (pPlayable && pPlayable->GetSolo())
return true;
}
return false;
}
#ifdef EXPERIMENTAL_MIDI_OUT
void MixerBoard::RefreshTrackCluster(const Track* pTrack, bool bEraseBackground /*= true*/)
#else
void MixerBoard::RefreshTrackCluster(const WaveTrack* pTrack, bool bEraseBackground )
#endif
void MixerBoard::RefreshTrackCluster(const PlayableTrack* pTrack, bool bEraseBackground /*= true*/)
{
MixerTrackCluster* pMixerTrackCluster;
this->FindMixerTrackCluster(pTrack, &pMixerTrackCluster);
@ -1277,11 +1153,7 @@ void MixerBoard::ResetMeters(const bool bResetClipping)
mMixerTrackClusters[i]->ResetMeter(bResetClipping);
}
#ifdef EXPERIMENTAL_MIDI_OUT
void MixerBoard::UpdateName(const Track* pTrack)
#else
void MixerBoard::UpdateName(const WaveTrack* pTrack)
#endif
void MixerBoard::UpdateName(const PlayableTrack* pTrack)
{
MixerTrackCluster* pMixerTrackCluster;
this->FindMixerTrackCluster(pTrack, &pMixerTrackCluster);
@ -1289,11 +1161,7 @@ void MixerBoard::UpdateName(const WaveTrack* pTrack)
pMixerTrackCluster->UpdateName();
}
#ifdef EXPERIMENTAL_MIDI_OUT
void MixerBoard::UpdateMute(const Track* pTrack /*= NULL*/) // NULL means update for all tracks.
#else
void MixerBoard::UpdateMute(const WaveTrack* pTrack /*= NULL*/) // NULL means update for all tracks.
#endif
void MixerBoard::UpdateMute(const PlayableTrack* pTrack /*= NULL*/) // NULL means update for all tracks.
{
if (pTrack == NULL)
{
@ -1309,11 +1177,7 @@ void MixerBoard::UpdateMute(const WaveTrack* pTrack /*= NULL*/) // NULL means up
}
}
#ifdef EXPERIMENTAL_MIDI_OUT
void MixerBoard::UpdateSolo(const Track* pTrack /*= NULL*/) // NULL means update for all tracks.
#else
void MixerBoard::UpdateSolo(const WaveTrack* pTrack /*= NULL*/) // NULL means update for all tracks.
#endif
void MixerBoard::UpdateSolo(const PlayableTrack* pTrack /*= NULL*/) // NULL means update for all tracks.
{
if (pTrack == NULL)
{
@ -1329,11 +1193,7 @@ void MixerBoard::UpdateSolo(const WaveTrack* pTrack /*= NULL*/) // NULL means up
}
}
#ifdef EXPERIMENTAL_MIDI_OUT
void MixerBoard::UpdatePan(const Track* pTrack)
#else
void MixerBoard::UpdatePan(const WaveTrack* pTrack)
#endif
void MixerBoard::UpdatePan(const PlayableTrack* pTrack)
{
MixerTrackCluster* pMixerTrackCluster;
FindMixerTrackCluster(pTrack, &pMixerTrackCluster);
@ -1341,11 +1201,7 @@ void MixerBoard::UpdatePan(const WaveTrack* pTrack)
pMixerTrackCluster->UpdatePan();
}
#ifdef EXPERIMENTAL_MIDI_OUT
void MixerBoard::UpdateGain(const Track* pTrack)
#else
void MixerBoard::UpdateGain(const WaveTrack* pTrack)
#endif
void MixerBoard::UpdateGain(const PlayableTrack* pTrack)
{
MixerTrackCluster* pMixerTrackCluster;
FindMixerTrackCluster(pTrack, &pMixerTrackCluster);
@ -1471,22 +1327,13 @@ void MixerBoard::CreateMuteSoloImages()
mImageSoloDisabled = std::make_unique<wxImage>(mMuteSoloWidth, MUTE_SOLO_HEIGHT); // Leave empty because unused.
}
#ifdef EXPERIMENTAL_MIDI_OUT
int MixerBoard::FindMixerTrackCluster(const Track* pTrack,
MixerTrackCluster** hMixerTrackCluster) const
#else
int MixerBoard::FindMixerTrackCluster(const WaveTrack* pLeftTrack,
int MixerBoard::FindMixerTrackCluster(const PlayableTrack* pTrack,
MixerTrackCluster** hMixerTrackCluster) const
#endif
{
*hMixerTrackCluster = NULL;
for (unsigned int i = 0; i < mMixerTrackClusters.GetCount(); i++)
{
#ifdef EXPERIMENTAL_MIDI_OUT
if (mMixerTrackClusters[i]->mTrack == pTrack)
#else
if (mMixerTrackClusters[i]->mLeftTrack == pLeftTrack)
#endif
{
*hMixerTrackCluster = mMixerTrackClusters[i];
return i;

View File

@ -62,10 +62,11 @@ public:
class AudacityProject;
class Meter;
class MixerBoard;
#ifdef EXPERIMENTAL_MIDI_OUT
class Track;
class NoteTrack;
#endif
class PlayableTrack;
class WaveTrack;
class MixerTrackCluster final : public wxPanelWrapper
@ -73,11 +74,15 @@ class MixerTrackCluster final : public wxPanelWrapper
public:
MixerTrackCluster(wxWindow* parent,
MixerBoard* grandParent, AudacityProject* project,
WaveTrack* pLeftTrack, WaveTrack* pRightTrack = NULL,
PlayableTrack* pTrack,
const wxPoint& pos = wxDefaultPosition,
const wxSize& size = wxDefaultSize);
virtual ~MixerTrackCluster() {}
WaveTrack *GetWave() const;
WaveTrack *GetRight() const;
NoteTrack *GetNote() const;
void UpdatePrefs();
void HandleResize(); // For wxSizeEvents, update gain slider and meter.
@ -115,23 +120,7 @@ private:
public:
#ifdef EXPERIMENTAL_MIDI_OUT
// mTrack is redundant, but simplifies code that operates on either
// mLeftTrack or mNoteTrack.
Track* mTrack; // either mLeftTrack or mNoteTrack, whichever is not NULL
#endif
WaveTrack* mLeftTrack; // NULL if Note Track
WaveTrack* mRightTrack; // NULL if mono
//vvv Vaughan, 2010-11-05:
// I suggest that when this is no longer experimental, rather than all these #ifdef's,
// this be done by factoring, i.e., add two subclasses to MixerTrackCluster,
// MixerNoteTrackCluster and MixerWaveTrackCluster, such that all the common
// code is in the parent, and these #ifdef's are only around
// MixerNoteTrackCluster rather than sprinkled throughout MixerTrackCluster.
#ifdef EXPERIMENTAL_MIDI_OUT
NoteTrack* mNoteTrack; // NULL if Wave Track
#endif
PlayableTrack * mTrack;
private:
MixerBoard* mMixerBoard;
@ -213,45 +202,26 @@ public:
void UpdateTrackClusters();
int GetTrackClustersWidth();
#ifdef EXPERIMENTAL_MIDI_OUT
void MoveTrackCluster(const Track* pTrack, bool bUp); // Up in TrackPanel is left in MixerBoard.
void RemoveTrackCluster(const Track* pTrack);
void MoveTrackCluster(const PlayableTrack* pTrack, bool bUp); // Up in TrackPanel is left in MixerBoard.
void RemoveTrackCluster(const PlayableTrack* pTrack);
void RemoveTrackCluster(size_t nIndex);
wxBitmap* GetMusicalInstrumentBitmap(const wxString & name);
#else
void MoveTrackCluster(const WaveTrack* pTrack, bool bUp); // Up in TrackPanel is left in MixerBoard.
void RemoveTrackCluster(const WaveTrack* pTrack);
wxBitmap* GetMusicalInstrumentBitmap(const WaveTrack* pLeftTrack);
#endif
wxBitmap* GetMusicalInstrumentBitmap(const Track *pTrack);
bool HasSolo();
#ifdef EXPERIMENTAL_MIDI_OUT
void RefreshTrackCluster(const Track* pTrack, bool bEraseBackground = true);
#else
void RefreshTrackCluster(const WaveTrack* pTrack, bool bEraseBackground = true);
#endif
void RefreshTrackCluster(const PlayableTrack* pTrack, bool bEraseBackground = true);
void RefreshTrackClusters(bool bEraseBackground = true);
void ResizeTrackClusters();
void ResetMeters(const bool bResetClipping);
#ifdef EXPERIMENTAL_MIDI_OUT
void UpdateName(const Track* pTrack);
void UpdateMute(const Track* pTrack = NULL); // NULL means update for all tracks.
void UpdateSolo(const Track* pTrack = NULL); // NULL means update for all tracks.
void UpdatePan(const Track* pTrack);
void UpdateGain(const Track* pTrack);
#else
void UpdateName(const WaveTrack* pTrack);
void UpdateMute(const WaveTrack* pTrack = NULL); // NULL means update for all tracks.
void UpdateSolo(const WaveTrack* pTrack = NULL); // NULL means update for all tracks.
void UpdatePan(const WaveTrack* pTrack);
void UpdateGain(const WaveTrack* pTrack);
#endif
void UpdateName(const PlayableTrack* pTrack);
void UpdateMute(const PlayableTrack* pTrack = NULL); // NULL means update for all tracks.
void UpdateSolo(const PlayableTrack* pTrack = NULL); // NULL means update for all tracks.
void UpdatePan(const PlayableTrack* pTrack);
void UpdateGain(const PlayableTrack* pTrack);
void UpdateMeters(const double t1, const bool bLoopedPlay);
@ -259,13 +229,8 @@ public:
private:
void CreateMuteSoloImages();
#ifdef EXPERIMENTAL_MIDI_OUT
int FindMixerTrackCluster(const Track* pTrack,
int FindMixerTrackCluster(const PlayableTrack* pTrack,
MixerTrackCluster** hMixerTrackCluster) const;
#else
int FindMixerTrackCluster(const WaveTrack* pLeftTrack,
MixerTrackCluster** hMixerTrackCluster) const;
#endif
void LoadMusicalInstruments();
// event handlers

View File

@ -103,8 +103,8 @@ NoteTrack::Holder TrackFactory::NewNoteTrack()
return std::make_unique<NoteTrack>(mDirManager);
}
NoteTrack::NoteTrack(const std::shared_ptr<DirManager> &projDirManager):
Track(projDirManager)
NoteTrack::NoteTrack(const std::shared_ptr<DirManager> &projDirManager)
: NoteTrackBase(projDirManager)
{
SetDefaultName(_("Note Track"));
SetName(GetDefaultName());
@ -113,7 +113,7 @@ Track(projDirManager)
mSerializationLength = 0;
#ifdef EXPERIMENTAL_MIDI_OUT
mGain = 0;
mVelocity = 0;
#endif
mBottomNote = 24;
mPitchHeight = 5;
@ -137,7 +137,7 @@ Track::Holder NoteTrack::Duplicate() const
// project object.
if (mSeq) {
SonifyBeginSerialize();
assert(!mSerializationBuffer);
wxASSERT(!mSerializationBuffer);
// serialize from this to duplicate's mSerializationBuffer
void *buffer;
mSeq->serialize(&buffer,
@ -146,13 +146,13 @@ Track::Holder NoteTrack::Duplicate() const
SonifyEndSerialize();
} else if (mSerializationBuffer) {
SonifyBeginUnserialize();
assert(!mSeq);
wxASSERT(!mSeq);
std::unique_ptr<Alg_track> alg_track{ Alg_seq::unserialize(mSerializationBuffer.get(),
mSerializationLength) };
assert(alg_track->get_type() == 's');
wxASSERT(alg_track->get_type() == 's');
duplicate->mSeq.reset(static_cast<Alg_seq*>(alg_track.release()));
SonifyEndUnserialize();
} else assert(false); // bug if neither mSeq nor mSerializationBuffer
} else wxFAIL_MSG("neither mSeq nor mSerializationBuffer were present"); // bug if neither mSeq nor mSerializationBuffer
// copy some other fields here
duplicate->SetBottomNote(mBottomNote);
duplicate->SetPitchHeight(mPitchHeight);
@ -160,7 +160,7 @@ Track::Holder NoteTrack::Duplicate() const
duplicate->mVisibleChannels = mVisibleChannels;
duplicate->SetOffset(GetOffset());
#ifdef EXPERIMENTAL_MIDI_OUT
duplicate->SetGain(GetGain());
duplicate->SetVelocity(GetVelocity());
#endif
// This std::move is needed to "upcast" the pointer type
return std::move(duplicate);
@ -239,7 +239,7 @@ void NoteTrack::WarpAndTransposeNotes(double t0, double t1,
int NoteTrack::DrawLabelControls(wxDC & dc, wxRect & r)
int NoteTrack::DrawLabelControls(wxDC & dc, const wxRect &r)
{
int wid = 23;
int ht = 16;
@ -328,7 +328,7 @@ int NoteTrack::DrawLabelControls(wxDC & dc, wxRect & r)
return box.GetBottom();
}
bool NoteTrack::LabelClick(wxRect & r, int mx, int my, bool right)
bool NoteTrack::LabelClick(const wxRect &r, int mx, int my, bool right)
{
int wid = 23;
int ht = 16;
@ -758,6 +758,8 @@ bool NoteTrack::HandleXMLTag(const wxChar *tag, const wxChar **attrs)
double dblValue;
if (!wxStrcmp(attr, wxT("name")) && XMLValueChecker::IsGoodString(strValue))
mName = strValue;
else if (this->NoteTrackBase::HandleXMLAttribute(attr, value))
{}
else if (!wxStrcmp(attr, wxT("offset")) &&
XMLValueChecker::IsGoodString(strValue) &&
Internat::CompatibleToDouble(strValue, &dblValue))
@ -782,7 +784,7 @@ bool NoteTrack::HandleXMLTag(const wxChar *tag, const wxChar **attrs)
else if (!wxStrcmp(attr, wxT("velocity")) &&
XMLValueChecker::IsGoodString(strValue) &&
Internat::CompatibleToDouble(strValue, &dblValue))
mGain = (float) dblValue;
mVelocity = (float) dblValue;
#endif
else if (!wxStrcmp(attr, wxT("bottomnote")) &&
XMLValueChecker::IsGoodInt(strValue) && strValue.ToLong(&nValue))
@ -826,11 +828,12 @@ void NoteTrack::WriteXML(XMLWriter &xmlFile) const
if (!mSeq) { // replace saveme with an (unserialized) duplicate
holder = Duplicate();
saveme = static_cast<NoteTrack*>(holder.get());
assert(saveme->mSeq);
wxASSERT(saveme->mSeq);
}
saveme->mSeq->write(data, true);
xmlFile.StartTag(wxT("notetrack"));
xmlFile.WriteAttr(wxT("name"), saveme->mName);
this->NoteTrackBase::WriteXMLAttributes(xmlFile);
xmlFile.WriteAttr(wxT("offset"), saveme->GetOffset());
xmlFile.WriteAttr(wxT("visiblechannels"), saveme->mVisibleChannels);
xmlFile.WriteAttr(wxT("height"), saveme->GetActualHeight());
@ -838,7 +841,7 @@ void NoteTrack::WriteXML(XMLWriter &xmlFile) const
xmlFile.WriteAttr(wxT("isSelected"), this->GetSelected());
#ifdef EXPERIMENTAL_MIDI_OUT
xmlFile.WriteAttr(wxT("velocity"), (double) saveme->mGain);
xmlFile.WriteAttr(wxT("velocity"), (double) saveme->mVelocity);
#endif
xmlFile.WriteAttr(wxT("bottomnote"), saveme->mBottomNote);
xmlFile.WriteAttr(wxT("data"), wxString(data.str().c_str(), wxConvUTF8));

View File

@ -50,7 +50,17 @@ class wxRect;
class DirManager;
class Alg_seq; // from "allegro.h"
class AUDACITY_DLL_API NoteTrack final : public Track {
using NoteTrackBase =
#ifdef EXPERIMENTAL_MIDI_OUT
PlayableTrack
#else
AudioTrack
#endif
;
class AUDACITY_DLL_API NoteTrack final
: public NoteTrackBase
{
public:
friend class TrackArtist;
@ -69,8 +79,8 @@ class AUDACITY_DLL_API NoteTrack final : public Track {
void WarpAndTransposeNotes(double t0, double t1,
const TimeWarper &warper, double semitones);
int DrawLabelControls(wxDC & dc, wxRect & r);
bool LabelClick(wxRect & r, int x, int y, bool right);
int DrawLabelControls(wxDC & dc, const wxRect &r);
bool LabelClick(const wxRect &rect, int x, int y, bool right);
void SetSequence(std::unique_ptr<Alg_seq> &&seq);
Alg_seq* GetSequence();
@ -98,8 +108,8 @@ class AUDACITY_DLL_API NoteTrack final : public Track {
bool Shift(double t) /* not override */;
#ifdef EXPERIMENTAL_MIDI_OUT
float GetGain() const { return mGain; }
void SetGain(float gain) { mGain = gain; }
float GetVelocity() const { return mVelocity; }
void SetVelocity(float velocity) { mVelocity = velocity; }
#endif
double NearestBeatTime(double time, double *beat) const;
@ -202,7 +212,7 @@ class AUDACITY_DLL_API NoteTrack final : public Track {
long mSerializationLength;
#ifdef EXPERIMENTAL_MIDI_OUT
float mGain; // velocity offset
float mVelocity; // velocity offset
#endif
// mBottom is the Y offset of pitch 0 (normally off screen)

View File

@ -2800,7 +2800,7 @@ wxArrayString AudacityProject::ShowOpenDialog(const wxString &extraformat, const
wxArrayString selected;
FileDialog dlog(NULL,
_("Select one or more audio files..."),
_("Select one or more files"),
path,
wxT(""),
mask,
@ -3655,6 +3655,8 @@ void AudacityProject::WriteXML(XMLWriter &xmlFile, bool bWantSaveCompressed)
while (t) {
if ((t->GetKind() == Track::Wave) && bWantSaveCompressed)
{
auto wt = static_cast<const WaveTrack *>(t);
//vvv This should probably be a method, WaveTrack::WriteCompressedTrackXML().
xmlFile.StartTag(wxT("import"));
xmlFile.WriteAttr(wxT("filename"), mStrOtherNamesArray[ndx]); // Assumes mTracks order hasn't changed!
@ -3665,8 +3667,8 @@ void AudacityProject::WriteXML(XMLWriter &xmlFile, bool bWantSaveCompressed)
// xmlFile.WriteAttr(wxT("linked"), t->GetLinked());
xmlFile.WriteAttr(wxT("offset"), t->GetOffset(), 8);
xmlFile.WriteAttr(wxT("mute"), t->GetMute());
xmlFile.WriteAttr(wxT("solo"), t->GetSolo());
xmlFile.WriteAttr(wxT("mute"), wt->GetMute());
xmlFile.WriteAttr(wxT("solo"), wt->GetSolo());
xmlFile.WriteAttr(wxT("height"), t->GetActualHeight());
xmlFile.WriteAttr(wxT("minimized"), t->GetMinimized());
@ -3975,10 +3977,12 @@ bool AudacityProject::Save(bool overwrite /* = true */ ,
((pTrack != NULL) && (pSavedTrack != NULL));
pTrack = iter.Next(), pSavedTrack = savedTrackIter.Next())
{
pWaveTrack = (WaveTrack*)pTrack;
pWaveTrack = static_cast<WaveTrack*>(pTrack);
auto pSavedWaveTrack = static_cast<const WaveTrack*>(pSavedTrack);
pWaveTrack->SetSelected(pSavedTrack->GetSelected());
pWaveTrack->SetMute(pSavedTrack->GetMute());
pWaveTrack->SetSolo(pSavedTrack->GetSolo());
pWaveTrack->SetMute(pSavedWaveTrack->GetMute());
pWaveTrack->SetSolo(pSavedWaveTrack->GetSolo());
pWaveTrack->SetGain(((WaveTrack*)pSavedTrack)->GetGain());
pWaveTrack->SetPan(((WaveTrack*)pSavedTrack)->GetPan());
@ -5396,12 +5400,13 @@ void AudacityProject::RemoveTrack(Track * toRemove)
wxString name = toRemove->GetName();
Track *partner = toRemove->GetLink();
if (toRemove->GetKind() == Track::Wave)
auto playable = dynamic_cast<PlayableTrack*>(toRemove);
if (playable)
{
// Update mixer board displayed tracks.
MixerBoard* pMixerBoard = this->GetMixerBoard();
if (pMixerBoard)
pMixerBoard->RemoveTrackCluster((WaveTrack*)toRemove); // Will remove partner shown in same cluster.
pMixerBoard->RemoveTrackCluster(playable); // Will remove partner shown in same cluster.
}
mTracks->Remove(toRemove);
@ -5429,36 +5434,45 @@ void AudacityProject::HandleTrackMute(Track *t, const bool exclusive)
if (exclusive)
{
TrackListIterator iter(GetTracks());
Track *i = iter.First();
while (i) {
if (i == t) {
i->SetMute(true);
if(i->GetLinked()) { // also mute the linked track
i = iter.Next();
Track *it = iter.First();
while (it) {
auto i = dynamic_cast<PlayableTrack *>(it);
if (i) {
if (i == t) {
i->SetMute(true);
if(i->GetLinked()) { // also mute the linked track
it = iter.Next();
i->SetMute(true);
}
}
else {
i->SetMute(false);
}
i->SetSolo(false);
}
else {
i->SetMute(false);
}
i->SetSolo(false);
i = iter.Next();
it = iter.Next();
}
}
else
{
// Normal click toggles this track.
t->SetMute(!t->GetMute());
auto pt = dynamic_cast<PlayableTrack *>( t );
if (!pt)
return;
pt->SetMute(!pt->GetMute());
if(t->GetLinked()) // set mute the same on both, if a pair
{
bool muted = t->GetMute();
bool muted = pt->GetMute();
TrackListIterator iter(GetTracks());
Track *i = iter.First();
while (i != t) { // search for this track
i = iter.Next();
}
i = iter.Next(); // get the next one, since linked
i->SetMute(muted); // and mute it as well
auto pi = dynamic_cast<PlayableTrack *>( i );
if (pi)
pi->SetMute(muted); // and mute it as well
}
if (IsSoloSimple() || IsSoloNone())
@ -5470,18 +5484,23 @@ void AudacityProject::HandleTrackMute(Track *t, const bool exclusive)
// We also set a solo indicator if we have just one track / stereo pair playing.
// otherwise clear solo on everything.
while (i) {
if( !i->GetMute())
{
nPlaying += 1;
if(i->GetLinked())
i = iter.Next(); // don't count this one as it is linked
auto pi = dynamic_cast<PlayableTrack *>( i );
if (pi) {
if( !pi->GetMute())
{
nPlaying += 1;
if(i->GetLinked())
i = iter.Next(); // don't count this one as it is linked
}
}
i = iter.Next();
}
i = iter.First();
while (i) {
i->SetSolo( (nPlaying==1) && !i->GetMute() ); // will set both of a stereo pair
auto pi = dynamic_cast<PlayableTrack *>( i );
if (pi)
pi->SetSolo( (nPlaying==1) && !pi->GetMute() ); // will set both of a stereo pair
i = iter.Next();
}
}
@ -5491,8 +5510,12 @@ void AudacityProject::HandleTrackMute(Track *t, const bool exclusive)
// Type of solo (standard or simple) follows the set preference, unless
// alternate == true, which causes the opposite behavior.
void AudacityProject::HandleTrackSolo(Track *t, const bool alternate)
void AudacityProject::HandleTrackSolo(Track *const t, const bool alternate)
{
const auto pt = dynamic_cast<PlayableTrack *>( t );
if (!pt)
return;
bool bSoloMultiple = !IsSoloSimple() ^ alternate;
// Standard and Simple solo have opposite defaults:
@ -5502,17 +5525,19 @@ void AudacityProject::HandleTrackSolo(Track *t, const bool alternate)
// when in standard radio button mode.
if ( bSoloMultiple )
{
t->SetSolo( !t->GetSolo() );
pt->SetSolo( !pt->GetSolo() );
if(t->GetLinked())
{
bool soloed = t->GetSolo();
bool soloed = pt->GetSolo();
TrackListIterator iter(GetTracks());
Track *i = iter.First();
while (i != t) { // search for this track
i = iter.Next();
}
i = iter.Next(); // get the next one, since linked
i->SetSolo(soloed); // and solo it as well
auto pi = dynamic_cast<PlayableTrack *>( i );
if (pi)
pi->SetSolo(soloed); // and solo it as well
}
}
else
@ -5521,26 +5546,32 @@ void AudacityProject::HandleTrackSolo(Track *t, const bool alternate)
// OR unmute and unsolo everything.
TrackListIterator iter(GetTracks());
Track *i = iter.First();
bool bWasSolo = t->GetSolo();
bool bWasSolo = pt->GetSolo();
while (i) {
if( i==t )
{
i->SetSolo(!bWasSolo);
pt->SetSolo(!bWasSolo);
if( IsSoloSimple() )
i->SetMute(false);
pt->SetMute(false);
if(t->GetLinked())
{
i = iter.Next();
i->SetSolo(!bWasSolo);
if( IsSoloSimple() )
i->SetMute(false);
auto pi = dynamic_cast<PlayableTrack *>( i );
if (pi) {
pi->SetSolo(!bWasSolo);
if( IsSoloSimple() )
pi->SetMute(false);
}
}
}
else
{
i->SetSolo(false);
if( IsSoloSimple() )
i->SetMute(!bWasSolo);
auto pi = dynamic_cast<PlayableTrack *>( i );
if (pi) {
pi->SetSolo(false);
if( IsSoloSimple() )
pi->SetMute(!bWasSolo);
}
}
i = iter.Next();
}

View File

@ -378,8 +378,10 @@ float Sequence::GetRMS(sampleCount start, sampleCount len, bool mayThrow) const
std::unique_ptr<Sequence> Sequence::Copy(sampleCount s0, sampleCount s1) const
{
if (s0 >= s1 || s0 >= mNumSamples || s1 < 0)
return {};
auto dest = std::make_unique<Sequence>(mDirManager, mSampleFormat);
if (s0 >= s1 || s0 >= mNumSamples || s1 < 0) {
return dest;
}
int numBlocks = mBlock.size();
@ -391,7 +393,6 @@ std::unique_ptr<Sequence> Sequence::Copy(sampleCount s0, sampleCount s1) const
wxUnusedVar(numBlocks);
wxASSERT(b0 <= b1);
auto dest = std::make_unique<Sequence>(mDirManager, mSampleFormat);
dest->mBlock.reserve(b1 - b0 + 1);
SampleBuffer buffer(mMaxSamples, mSampleFormat);

View File

@ -50,8 +50,6 @@ Track::Track(const std::shared_ptr<DirManager> &projDirManager)
mList = NULL;
mSelected = false;
mLinked = false;
mMute = false;
mSolo = false;
mY = 0;
mHeight = 150;
@ -92,8 +90,6 @@ void Track::Init(const Track &orig)
mSelected = orig.mSelected;
mLinked = orig.mLinked;
mMute = orig.mMute;
mSolo = orig.mSolo;
mHeight = orig.mHeight;
mMinimized = orig.mMinimized;
mChannel = orig.mChannel;
@ -112,8 +108,6 @@ void Track::SetSelected(bool s)
void Track::Merge(const Track &orig)
{
mSelected = orig.mSelected;
mMute = orig.mMute;
mSolo = orig.mSolo;
}
Track::~Track()
@ -331,6 +325,49 @@ bool Track::SyncLockAdjust(double oldT1, double newT1)
return true;
}
void PlayableTrack::Init( const PlayableTrack &orig )
{
mMute = orig.mMute;
mSolo = orig.mSolo;
AudioTrack::Init( orig );
}
void PlayableTrack::Merge( const Track &orig )
{
auto pOrig = dynamic_cast<const PlayableTrack *>(&orig);
wxASSERT( pOrig );
mMute = pOrig->mMute;
mSolo = pOrig->mSolo;
AudioTrack::Merge( *pOrig );
}
// Serialize, not with tags of its own, but as attributes within a tag.
void PlayableTrack::WriteXMLAttributes(XMLWriter &xmlFile) const
{
xmlFile.WriteAttr(wxT("mute"), mMute);
xmlFile.WriteAttr(wxT("solo"), mSolo);
AudioTrack::WriteXMLAttributes(xmlFile);
}
// Return true iff the attribute is recognized.
bool PlayableTrack::HandleXMLAttribute(const wxChar *attr, const wxChar *value)
{
const wxString strValue{ value };
long nValue;
if (!wxStrcmp(attr, wxT("mute")) &&
XMLValueChecker::IsGoodInt(strValue) && strValue.ToLong(&nValue)) {
mMute = (nValue != 0);
return true;
}
else if (!wxStrcmp(attr, wxT("solo")) &&
XMLValueChecker::IsGoodInt(strValue) && strValue.ToLong(&nValue)) {
mSolo = (nValue != 0);
return true;
}
return AudioTrack::HandleXMLAttribute(attr, value);
}
// TrackListIterator
TrackListIterator::TrackListIterator(TrackList * val)
: l(val)
@ -579,16 +616,9 @@ SyncLockedTracksIterator::SyncLockedTracksIterator(TrackList * val)
}
namespace {
bool IsSyncLockableNonLabelTrack( const Track *pTrack )
inline bool IsSyncLockableNonLabelTrack( const Track *pTrack )
{
if ( pTrack->GetKind() == Track::Wave )
return true;
#ifdef USE_MIDI
else if ( pTrack->GetKind() == Track::Note )
return true;
#endif
else
return false;
return nullptr != dynamic_cast< const AudioTrack * >( pTrack );
}
}
@ -1208,7 +1238,9 @@ unsigned TrackList::GetNumExportChannels(bool selectionOnly) const
for (tr = iter.First(this); tr != NULL; tr = iter.Next()) {
// Want only unmuted wave tracks.
if ((tr->GetKind() != Track::Wave) || tr->GetMute())
auto wt = static_cast<const WaveTrack *>(tr);
if ((tr->GetKind() != Track::Wave) ||
wt->GetMute())
continue;
// do we only want selected ones?
@ -1265,8 +1297,9 @@ namespace {
for (; p != end; ++p) {
const auto &track = *p;
auto wt = static_cast<const WaveTrack *>(&*track);
if (track->GetKind() == Track::Wave &&
(includeMuted || !track->GetMute()) &&
(includeMuted || !wt->GetMute()) &&
(track->GetSelected() || !selectionOnly)) {
waveTrackArray.push_back(static_cast<WaveTrack*>(track.get()));
}

View File

@ -140,8 +140,6 @@ class AUDACITY_DLL_API Track /* not final */ : public XMLTagHandler
protected:
int mChannel;
double mOffset;
bool mMute;
bool mSolo;
mutable std::shared_ptr<DirManager> mDirManager;
@ -189,14 +187,10 @@ class AUDACITY_DLL_API Track /* not final */ : public XMLTagHandler
void SetDefaultName( const wxString &n ) { mDefaultName = n; }
bool GetSelected() const { return mSelected; }
bool GetMute () const { return mMute; }
bool GetLinked () const { return mLinked; }
bool GetSolo () const { return mSolo; }
virtual void SetSelected(bool s);
void SetMute (bool m) { mMute = m; }
void SetLinked (bool l);
void SetSolo (bool s) { mSolo = s; }
int GetChannel() const { return mChannel; }
virtual double GetOffset() const = 0;
@ -251,6 +245,47 @@ class AUDACITY_DLL_API Track /* not final */ : public XMLTagHandler
bool IsSyncLockSelected() const;
};
class AudioTrack /* not final */ : public Track
{
public:
AudioTrack(const std::shared_ptr<DirManager> &projDirManager)
: Track{ projDirManager } {}
AudioTrack(const Track &orig) : Track{ orig } {}
// Serialize, not with tags of its own, but as attributes within a tag.
void WriteXMLAttributes(XMLWriter &xmlFile) const {}
// Return true iff the attribute is recognized.
bool HandleXMLAttribute(const wxChar * /*attr*/, const wxChar * /*value*/)
{ return false; }
};
class PlayableTrack /* not final */ : public AudioTrack
{
public:
PlayableTrack(const std::shared_ptr<DirManager> &projDirManager)
: AudioTrack{ projDirManager } {}
PlayableTrack(const Track &orig) : AudioTrack{ orig } {}
bool GetMute () const { return mMute; }
bool GetSolo () const { return mSolo; }
void SetMute (bool m) { mMute = m; }
void SetSolo (bool s) { mSolo = s; }
void Init( const PlayableTrack &init );
void Merge( const Track &init ) override;
// Serialize, not with tags of its own, but as attributes within a tag.
void WriteXMLAttributes(XMLWriter &xmlFile) const;
// Return true iff the attribute is recognized.
bool HandleXMLAttribute(const wxChar *attr, const wxChar *value);
protected:
bool mMute { false };
bool mSolo { false };
};
class AUDACITY_DLL_API TrackListIterator /* not final */
{
public:

View File

@ -336,7 +336,8 @@ void TrackArtist::DrawTracks(TrackList * tracks,
bool hasSolo = false;
for (t = iter.First(); t; t = iter.Next()) {
if (t->GetSolo()) {
auto pt = dynamic_cast<const PlayableTrack *>(t);
if (pt && pt->GetSolo()) {
hasSolo = true;
break;
}
@ -457,7 +458,8 @@ void TrackArtist::DrawTrack(const Track * t,
clip->ClearDisplayRect();
}
bool muted = (hasSolo || t->GetMute()) && !t->GetSolo();
bool muted = (hasSolo || wt->GetMute()) &&
!wt->GetSolo();
#if defined(__WXMAC__)
wxAntialiasMode aamode = dc.GetGraphicsContext()->GetAntialiasMode();
@ -493,7 +495,11 @@ void TrackArtist::DrawTrack(const Track * t,
#ifdef USE_MIDI
case Track::Note:
{
bool muted = (hasSolo || t->GetMute()) && !t->GetSolo();
auto nt = static_cast<const NoteTrack *>(t);
bool muted = false;
#ifdef EXPERIMENTAL_MIDI_OUT
muted = (hasSolo || nt->GetMute()) && !nt->GetSolo();
#endif
DrawNoteTrack((NoteTrack *)t, dc, rect, selectedRegion, zoomInfo, muted);
break;
}
@ -2807,17 +2813,17 @@ void TrackArtist::DrawNoteTrack(const NoteTrack *track,
Alg_seq_ptr seq = track->mSeq.get();
if (!seq) {
assert(track->mSerializationBuffer);
wxASSERT(track->mSerializationBuffer);
// JKC: Previously this indirected via seq->, a NULL pointer.
// This was actually OK, since unserialize is a static function.
// Alg_seq:: is clearer.
std::unique_ptr<Alg_track> alg_track{ Alg_seq::unserialize(track->mSerializationBuffer.get(),
track->mSerializationLength) };
assert(alg_track->get_type() == 's');
wxASSERT(alg_track->get_type() == 's');
const_cast<NoteTrack*>(track)->mSeq.reset(seq = static_cast<Alg_seq*>(alg_track.release()));
track->mSerializationBuffer.reset();
}
assert(seq);
wxASSERT(seq);
int visibleChannels = track->mVisibleChannels;
if (!track->GetSelected())

View File

@ -3732,8 +3732,11 @@ void TrackPanel::DoSlide(wxMouseEvent & event)
#else
{
trySnap = true;
desiredSlideAmount = rint(mouseTrack->GetRate() * desiredSlideAmount) /
mouseTrack->GetRate(); // set it to a sample point
if (mouseTrack->GetKind() == Track::Wave) {
WaveTrack *mtw = (WaveTrack *)mouseTrack;
desiredSlideAmount = rint(mtw->GetRate() * desiredSlideAmount) /
mtw->GetRate(); // set it to a sample point
}
if (mSnapManager && mCapturedClip) {
clipLeft = mCapturedClip->GetStartTime() + desiredSlideAmount;
clipRight = mCapturedClip->GetEndTime() + desiredSlideAmount;
@ -4960,7 +4963,7 @@ void TrackPanel::HandleSliders(wxMouseEvent &event, bool pan)
// mCapturedTrack is not wave...
if (!pan) {
// .. so assume it is note
static_cast<NoteTrack*>(mCapturedTrack)->SetGain(newValue);
static_cast<NoteTrack*>(mCapturedTrack)->SetVelocity(newValue);
#ifdef EXPERIMENTAL_MIXER_BOARD
if (pMixerBoard)
// probably should modify UpdateGain to take a track that is
@ -5209,27 +5212,17 @@ void TrackPanel::HandleRearrange(wxMouseEvent & event)
if (event.m_y < mMoveUpThreshold || event.m_y < 0) {
mTracks->MoveUp(mCapturedTrack);
--mRearrangeCount;
#ifdef EXPERIMENTAL_MIDI_OUT
if (pMixerBoard && (mCapturedTrack->GetKind() == Track::Wave ||
mCapturedTrack->GetKind() == Track::Note))
pMixerBoard->MoveTrackCluster(mCapturedTrack, true /* up */);
#else
if (pMixerBoard && (mCapturedTrack->GetKind() == Track::Wave))
pMixerBoard->MoveTrackCluster((WaveTrack*)mCapturedTrack, true /* up */);
#endif
if (pMixerBoard)
if(auto pPlayable = dynamic_cast< const PlayableTrack* >( mCapturedTrack ))
pMixerBoard->MoveTrackCluster(pPlayable, true /* up */);
}
else if (event.m_y > mMoveDownThreshold || event.m_y > GetRect().GetHeight()) {
mTracks->MoveDown(mCapturedTrack);
++mRearrangeCount;
/* i18n-hint: a direction as in up or down.*/
#ifdef EXPERIMENTAL_MIDI_OUT
if (pMixerBoard && (mCapturedTrack->GetKind() == Track::Wave ||
mCapturedTrack->GetKind() == Track::Note))
pMixerBoard->MoveTrackCluster(mCapturedTrack, false /* down */);
#else
if (pMixerBoard && (mCapturedTrack->GetKind() == Track::Wave))
pMixerBoard->MoveTrackCluster((WaveTrack*)mCapturedTrack, false /* down */);
#endif
if (pMixerBoard)
if(auto pPlayable = dynamic_cast< const PlayableTrack* >( mCapturedTrack ))
pMixerBoard->MoveTrackCluster(pPlayable, false /* down */);
}
else
{
@ -9295,18 +9288,19 @@ void TrackInfo::DrawMuteSolo(wxDC * dc, const wxRect & rect, Track * t,
return; // don't draw mute and solo buttons, because they don't fit into track label
AColor::MediumTrackInfo( dc, t->GetSelected());
auto pt = dynamic_cast<const PlayableTrack *>(t);
if( solo )
{
if( t->GetSolo() )
if( pt && pt->GetSolo() )
{
AColor::Solo(dc, t->GetSolo(), t->GetSelected());
AColor::Solo(dc, pt->GetSolo(), t->GetSelected());
}
}
else
{
if( t->GetMute() )
if( pt && pt->GetMute() )
{
AColor::Mute(dc, t->GetMute(), t->GetSelected(), t->GetSolo());
AColor::Mute(dc, pt->GetMute(), t->GetSelected(), pt->GetSolo());
}
}
//(solo) ? AColor::Solo(dc, t->GetSolo(), t->GetSelected()) :
@ -9325,7 +9319,11 @@ void TrackInfo::DrawMuteSolo(wxDC * dc, const wxRect & rect, Track * t,
dc->GetTextExtent(str, &textWidth, &textHeight);
dc->DrawText(str, bev.x + (bev.width - textWidth) / 2, bev.y + (bev.height - textHeight) / 2);
AColor::BevelTrackInfo(*dc, (solo?t->GetSolo():t->GetMute()) == down, bev);
AColor::BevelTrackInfo(
*dc,
(solo ? pt->GetSolo() : (pt && pt->GetMute())) == down,
bev
);
if (solo && !down) {
// Update the mute button, which may be grayed out depending on
@ -9374,7 +9372,7 @@ void TrackInfo::DrawVelocitySlider(wxDC *dc, NoteTrack *t, wxRect rect) const
auto &gain = mGain; // mGains[index];
gain->SetStyle(VEL_SLIDER);
GainSlider(index)->Move(wxPoint(gainRect.x, gainRect.y));
GainSlider(index)->Set(t->GetGain());
GainSlider(index)->Set(t->GetVelocity());
GainSlider(index)->OnPaint(*dc
// , t->GetSelected()
);

View File

@ -353,15 +353,18 @@ wxAccStatus TrackPanelAx::GetName( int childId, wxString* name )
this is a Time track.*/
name->Append( wxT(" ") + wxString(_("Time Track")));
}
#ifdef USE_MIDI
else if (t->GetKind() == Track::Note)
{
/* i18n-hint: This is for screen reader software and indicates that
this is a Note track.*/
name->Append( wxT(" ") + wxString(_("Note Track")));
}
#endif
// LLL: Remove these during "refactor"
if( t->GetMute() )
auto pt = dynamic_cast<PlayableTrack *>(t);
if( pt && pt->GetMute() )
{
// The following comment also applies to the solo, selected,
// and synclockselected states.
@ -374,7 +377,7 @@ wxAccStatus TrackPanelAx::GetName( int childId, wxString* name )
name->Append( wxT(" ") + wxString(_( " Mute On" )) );
}
if( t->GetSolo() )
if( pt && pt->GetSolo() )
{
/* i18n-hint: This is for screen reader software and indicates that
on this track solo is on.*/
@ -545,12 +548,13 @@ wxAccStatus TrackPanelAx::GetValue( int WXUNUSED(childId), wxString* WXUNUSED(st
}
// LLL: Remove these during "refactor"
if( t->GetMute() )
auto pt = dynamic_cast<PlayableTrack *>(t);
if( pt && pt->GetMute() )
{
strValue->Append( _( " Mute On" ) );
}
if( t->GetSolo() )
if( pt && pt->GetSolo() )
{
strValue->Append( _( " Solo On" ) );
}

View File

@ -79,7 +79,7 @@ WaveTrack::Holder TrackFactory::NewWaveTrack(sampleFormat format, double rate)
}
WaveTrack::WaveTrack(const std::shared_ptr<DirManager> &projDirManager, sampleFormat format, double rate) :
Track(projDirManager)
PlayableTrack(projDirManager)
{
if (format == (sampleFormat)0)
{
@ -116,7 +116,7 @@ WaveTrack::WaveTrack(const std::shared_ptr<DirManager> &projDirManager, sampleFo
}
WaveTrack::WaveTrack(const WaveTrack &orig):
Track(orig)
PlayableTrack(orig)
, mpSpectrumSettings(orig.mpSpectrumSettings
? std::make_unique<SpectrogramSettings>(*orig.mpSpectrumSettings)
: nullptr
@ -141,7 +141,7 @@ WaveTrack::WaveTrack(const WaveTrack &orig):
// Copy the track metadata but not the contents.
void WaveTrack::Init(const WaveTrack &orig)
{
Track::Init(orig);
PlayableTrack::Init(orig);
mFormat = orig.mFormat;
mRate = orig.mRate;
mGain = orig.mGain;
@ -171,7 +171,7 @@ void WaveTrack::Merge(const Track &orig)
SetWaveformSettings
(wt.mpWaveformSettings ? std::make_unique<WaveformSettings>(*wt.mpWaveformSettings) : nullptr);
}
Track::Merge(orig);
PlayableTrack::Merge(orig);
}
WaveTrack::~WaveTrack()
@ -1685,12 +1685,8 @@ bool WaveTrack::HandleXMLTag(const wxChar *tag, const wxChar **attrs)
// track is created.
mLegacyProjectFileOffset = dblValue;
}
else if (!wxStrcmp(attr, wxT("mute")) &&
XMLValueChecker::IsGoodInt(strValue) && strValue.ToLong(&nValue))
mMute = (nValue != 0);
else if (!wxStrcmp(attr, wxT("solo")) &&
XMLValueChecker::IsGoodInt(strValue) && strValue.ToLong(&nValue))
mSolo = (nValue != 0);
else if (this->PlayableTrack::HandleXMLAttribute(attr, value))
{}
else if (!wxStrcmp(attr, wxT("height")) &&
XMLValueChecker::IsGoodInt(strValue) && strValue.ToLong(&nValue))
mHeight = nValue;
@ -1789,8 +1785,7 @@ void WaveTrack::WriteXML(XMLWriter &xmlFile) const
xmlFile.WriteAttr(wxT("name"), mName);
xmlFile.WriteAttr(wxT("channel"), mChannel);
xmlFile.WriteAttr(wxT("linked"), mLinked);
xmlFile.WriteAttr(wxT("mute"), mMute);
xmlFile.WriteAttr(wxT("solo"), mSolo);
this->PlayableTrack::WriteXMLAttributes(xmlFile);
#ifdef EXPERIMENTAL_OUTPUT_DISPLAY
int height;
if(MONO_PAN)

View File

@ -69,7 +69,7 @@ class Regions : public std::vector < Region > {};
class Envelope;
class AUDACITY_DLL_API WaveTrack final : public Track {
class AUDACITY_DLL_API WaveTrack final : public PlayableTrack {
private:

View File

@ -161,10 +161,12 @@ bool GetProjectInfoCommand::testLinked(const Track * track) const
bool GetProjectInfoCommand::testSolo(const Track * track) const
{
return track->GetSolo();
auto pt = dynamic_cast<const PlayableTrack *>(track);
return pt && pt->GetSolo();
}
bool GetProjectInfoCommand::testMute(const Track * track) const
{
return track->GetMute();
auto pt = dynamic_cast<const PlayableTrack *>(track);
return pt && pt->GetMute();
}

View File

@ -127,15 +127,17 @@ bool GetTrackInfoCommand::Apply(CommandExecutionContext context)
}
else if (mode.IsSameAs(wxT("Solo")))
{
if (t->GetKind() == Track::Wave)
SendBooleanStatus(t->GetSolo());
auto pt = dynamic_cast<const PlayableTrack *>(t);
if (pt)
SendBooleanStatus(pt->GetSolo());
else
SendBooleanStatus(false);
}
else if (mode.IsSameAs(wxT("Mute")))
{
if (t->GetKind() == Track::Wave)
SendBooleanStatus(t->GetMute());
auto pt = dynamic_cast<const PlayableTrack *>(t);
if (pt)
SendBooleanStatus(pt->GetMute());
else
SendBooleanStatus(false);
}

View File

@ -275,13 +275,19 @@ void ExploreMenu( wxMenu * pMenu, int Id, int depth ){
size_t lcnt = list.GetCount();
wxMenuItem * item;
wxString Label;
wxString Accel;
for (size_t lndx = 0; lndx < lcnt; lndx++) {
item = list.Item(lndx)->GetData();
Label = item->GetItemLabelText();
Accel = item->GetItemLabel();
if( Accel.Contains("\t") )
Accel = Accel.AfterLast('\t');
else
Accel = "";
if( item->IsSeparator() )
Label = "----";
wxLogDebug("%2i: %s", depth, Label );
wxLogDebug("%2i,%s,%s", depth, Label,Accel );
if (item->IsSubMenu()) {
pMenu = item->GetSubMenu();
ExploreMenu( pMenu, item->GetId(), depth+1 );

View File

@ -98,12 +98,14 @@ void SetProjectInfoCommand::setSelected(Track * trk, bool param) const
void SetProjectInfoCommand::setSolo(Track * trk, bool param) const
{
if(trk->GetKind() == Track::Wave)
trk->SetSolo(param);
auto pt = dynamic_cast<PlayableTrack *>(trk);
if (pt)
pt->SetSolo(param);
}
void SetProjectInfoCommand::setMute(Track * trk, bool param) const
{
if(trk->GetKind() == Track::Wave)
trk->SetMute(param);
auto pt = dynamic_cast<PlayableTrack *>(trk);
if (pt)
pt->SetMute(param);
}

View File

@ -539,7 +539,7 @@ bool NyquistEffect::Process()
mProps += wxString::Format(wxT("(putprop '*SYSTEM-TIME* \"%s\" 'DAY-NAME)\n"), now.GetWeekDayName(day).c_str());
// TODO: Document: Number of open projects
mProps += wxString::Format(wxT("(putprop '*PROJECT* %d 'PROJECTS)\n"), gAudacityProjects.size());
mProps += wxString::Format(wxT("(putprop '*PROJECT* %d 'PROJECTS)\n"), (int) gAudacityProjects.size());
// TODO: Document. NOTE: unnamed project returns an empty string.
mProps += wxString::Format(wxT("(putprop '*PROJECT* \"%s\" 'NAME)\n"), project->GetName().c_str());
@ -998,7 +998,6 @@ bool NyquistEffect::ProcessOne()
cmd += wxString::Format(wxT("(putprop '*SELECTION* (vector %s) 'PEAK)\n"), peakString) :
cmd += wxString::Format(wxT("(putprop '*SELECTION* %s 'PEAK)\n"), peakString);
// TODO: Documen, PEAK-LEVEL is deprecated as of 2.1.3.
// TODO: Document, PEAK-LEVEL is nil if NaN or INF.
if (!std::isinf(maxPeakLevel) && !std::isnan(maxPeakLevel) && (maxPeakLevel < FLT_MAX)) {
cmd += wxString::Format(wxT("(putprop '*SELECTION* (float %s) 'PEAK-LEVEL)\n"),

View File

@ -425,7 +425,9 @@ bool Exporter::ExamineTracks()
while (tr) {
if (tr->GetKind() == Track::Wave) {
if ( (tr->GetSelected() || !mSelectedOnly) && !tr->GetMute() ) { // don't count muted tracks
auto wt = static_cast<const WaveTrack *>(tr);
if ( (tr->GetSelected() || !mSelectedOnly) &&
!wt->GetMute() ) { // don't count muted tracks
mNumSelected++;
if (tr->GetChannel() == Track::LeftChannel) {
@ -1255,7 +1257,9 @@ ExportMixerDialog::ExportMixerDialog( const TrackList *tracks, bool selectedOnly
for( const Track *t = iter.First(); t; t = iter.Next() )
{
if( t->GetKind() == Track::Wave && ( t->GetSelected() || !selectedOnly ) && !t->GetMute() )
auto wt = static_cast<const WaveTrack *>(t);
if( t->GetKind() == Track::Wave && ( t->GetSelected() || !selectedOnly ) &&
!wt->GetMute() )
{
numTracks++;
const wxString sTrackName = (t->GetName()).Left(20);

View File

@ -1685,7 +1685,7 @@ ProgressResult ExportMP3::Export(AudacityProject *project,
gPrefs->Write(wxT("/MP3/MP3LibPath"), wxString(wxT("")));
gPrefs->Flush();
return false;
return ProgressResult::Cancelled;
}
#else
if (!exporter.LoadLibrary(parent, MP3Exporter::Maybe)) {

View File

@ -154,7 +154,8 @@ void ExportMultiple::CountTracksAndLabels()
// Count WaveTracks, and for linked pairs, count only the second of the pair.
case Track::Wave:
{
if (!pTrack->GetMute() && !pTrack->GetLinked()) // Don't count muted tracks.
auto wt = static_cast<const WaveTrack *>(pTrack);
if (!wt->GetMute() && !pTrack->GetLinked()) // Don't count muted tracks.
mNumWaveTracks++;
break;
}
@ -811,7 +812,9 @@ ProgressResult ExportMultiple::ExportMultipleByTrack(bool byName,
for (tr = iter.First(mTracks); tr != NULL; tr = iter.Next()) {
// Want only non-muted wave tracks.
if ((tr->GetKind() != Track::Wave) || tr->GetMute())
auto wt = static_cast<const WaveTrack *>(tr);
if ((tr->GetKind() != Track::Wave) ||
wt->GetMute())
continue;
// Get the times for the track
@ -898,7 +901,8 @@ ProgressResult ExportMultiple::ExportMultipleByTrack(bool byName,
for (tr = iter.First(mTracks); tr != NULL; tr = iter.Next()) {
// Want only non-muted wave tracks.
if ((tr->GetKind() != Track::Wave) || (tr->GetMute() == true)) {
auto wt = static_cast<const WaveTrack *>(tr);
if ((tr->GetKind() != Track::Wave) || (wt->GetMute())) {
continue;
}

View File

@ -175,8 +175,10 @@ void MidiIOPrefs::PopulateOrExchange( ShuttleGui & S ) {
void MidiIOPrefs::OnHost(wxCommandEvent & e)
{
wxString itemAtIndex;
int index = mHost->GetCurrentSelection();
wxString itemAtIndex = mHostNames.Item(index);
if (index >= 0 && index < mHostNames.Count())
itemAtIndex = mHostNames.Item(index);
int nDevices = Pm_CountDevices();
if (nDevices == 0) {

View File

@ -224,11 +224,11 @@ void ControlToolBar::RegenerateTooltips()
break;
case ID_RECORD_BUTTON:
commands.push_back(wxT("Record"));
#ifndef EXPERIMENTAL_DA
#ifdef PREFER_NEW_TRACKS
commands.push_back(_("Append Record"));
commands.push_back(wxT("RecordAppend"));
#else
commands.push_back(_("Record Below"));
commands.push_back(_("Record New Track"));
commands.push_back(wxT("RecordBelow"));
#endif
break;
@ -418,11 +418,7 @@ void ControlToolBar::EnableDisableButtons()
if (p) {
TrackListIterator iter( p->GetTracks() );
for (Track *t = iter.First(); t; t = iter.Next()) {
if (t->GetKind() == Track::Wave
#if defined(USE_MIDI)
|| t->GetKind() == Track::Note
#endif
) {
if (dynamic_cast<const AudioTrack*>(t)) {
tracks = true;
break;
}
@ -874,7 +870,7 @@ void ControlToolBar::OnRecord(wxCommandEvent &evt)
bool success = false;
bool shifted = mRecord->WasShiftDown();
#ifdef EXPERIMENTAL_DA
#ifndef PREFER_NEW_TRACKS
shifted = !shifted;
#endif

View File

@ -44,9 +44,8 @@ class TipPanel;
#define DB_SLIDER 2 // -36...36 dB
#define PAN_SLIDER 3 // -1.0...1.0
#define SPEED_SLIDER 4 // 0.01 ..3.0
#ifdef EXPERIMENTAL_MIDI_OUT
#define VEL_SLIDER 5 // -50..50
#endif
#define DB_MIN -36.0f
#define DB_MAX 36.0f

View File

@ -351,6 +351,14 @@ KeyView::SetView(ViewByType type)
SelectNode(index);
}
#if 0
// JKC: Optional code to list commants and shortcuts to debug console.
int nLines = mLines.GetCount();
for(int i=0;i<nLines;i++){
wxLogDebug( "%i,%i,%s,%s", i, mLines[i]->depth, mLines[i]->label, mLines[i]->key );
}
#endif
return;
}

View File

@ -14,7 +14,8 @@ Authors:
Martyn Shaw
========================================================================
This document is for Audacity version 2.1.2.
This document is for Audacity version 2.1.3 and is currently also valid
for building 2.2.0-alpha.
If the advice here is inaccurate or incomplete,
email audacity-devel@lists.sourceforge.net.
@ -41,7 +42,7 @@ To simplify the implementation of a near-identical user
interface across platforms, Audacity uses wxWidgets, a
GUI framework.
Audacity 2.1.2 requires wxWidgets 3.0.2.
Audacity 2.1.3 requires wxWidgets 3.0.2.
To be able to build Audacity for Windows, download and install
wxWidgets from http://www.wxwidgets.org/.