mirror of
https://github.com/cookiengineer/audacity
synced 2025-07-14 07:37:43 +02:00
Merge release-3.0.3 into master
Conflicts: src/AboutDialog.cpp src/prefs/ApplicationPrefs.cpp
This commit is contained in:
commit
d0d64bf025
4
.github/workflows/cmake_build.yml
vendored
4
.github/workflows/cmake_build.yml
vendored
@ -74,9 +74,9 @@ jobs:
|
|||||||
cache-name: cache-conan-modules
|
cache-name: cache-conan-modules
|
||||||
with:
|
with:
|
||||||
path: ${{ env.CONAN_USER_HOME }}
|
path: ${{ env.CONAN_USER_HOME }}
|
||||||
key: host-${{ matrix.config.name }}-${{ hashFiles('cmake-proxies/CMakeLists.txt') }}
|
key: host-3-${{ matrix.config.name }}-${{ hashFiles('cmake-proxies/CMakeLists.txt') }}
|
||||||
restore-keys: |
|
restore-keys: |
|
||||||
host-${{ matrix.config.name }}-
|
host-3-${{ matrix.config.name }}-
|
||||||
|
|
||||||
- name: Configure
|
- name: Configure
|
||||||
env:
|
env:
|
||||||
|
@ -19,7 +19,7 @@ endif ()
|
|||||||
# still link to the alpha manual online.
|
# still link to the alpha manual online.
|
||||||
|
|
||||||
# Set this value to 0 for alpha, 1 for beta, 2 for release builds
|
# Set this value to 0 for alpha, 1 for beta, 2 for release builds
|
||||||
set( AUDACITY_BUILD_LEVEL 0 )
|
set( AUDACITY_BUILD_LEVEL 0 CACHE STRING "0 for alpha, 1 for beta, 2 for release builds" )
|
||||||
|
|
||||||
# The Audacity version
|
# The Audacity version
|
||||||
# Increment as appropriate after release of a new version, and set back
|
# Increment as appropriate after release of a new version, and set back
|
||||||
|
@ -246,7 +246,7 @@ namespace
|
|||||||
{
|
{
|
||||||
static constexpr int MaxUserCommentLength = 2000;
|
static constexpr int MaxUserCommentLength = 2000;
|
||||||
|
|
||||||
auto frame = new wxFrame(
|
auto dialog = new wxDialog(
|
||||||
nullptr,
|
nullptr,
|
||||||
wxID_ANY,
|
wxID_ANY,
|
||||||
_("Problem Report for Audacity"),
|
_("Problem Report for Audacity"),
|
||||||
@ -254,83 +254,89 @@ namespace
|
|||||||
wxDefaultSize,
|
wxDefaultSize,
|
||||||
wxDEFAULT_FRAME_STYLE & ~(wxRESIZE_BORDER | wxMAXIMIZE_BOX)//disable frame resize
|
wxDEFAULT_FRAME_STYLE & ~(wxRESIZE_BORDER | wxMAXIMIZE_BOX)//disable frame resize
|
||||||
);
|
);
|
||||||
frame->SetOwnBackgroundColour(wxSystemSettings::GetColour(wxSYS_COLOUR_FRAMEBK));
|
|
||||||
|
//fixes focus issue with Windows build-in screen reader, but breaks VoiceOver
|
||||||
|
#if defined(__WXMSW__)
|
||||||
|
dialog->SetFocus();
|
||||||
|
#endif
|
||||||
|
|
||||||
auto mainLayout = new wxBoxSizer(wxVERTICAL);
|
auto mainLayout = new wxBoxSizer(wxVERTICAL);
|
||||||
|
|
||||||
auto headerText = new wxStaticText(frame, wxID_ANY, header);
|
|
||||||
headerText->SetFont(wxFont(wxFontInfo().Bold()));
|
|
||||||
|
|
||||||
auto headerLayout = new wxBoxSizer(wxHORIZONTAL);
|
auto headerLayout = new wxBoxSizer(wxHORIZONTAL);
|
||||||
headerLayout->Add(new wxStaticBitmap(frame, wxID_ANY, wxIcon(warning)));
|
headerLayout->Add(new wxStaticBitmap(dialog, wxID_ANY, wxIcon(warning)));
|
||||||
headerLayout->AddSpacer(5);
|
headerLayout->AddSpacer(5);
|
||||||
|
|
||||||
|
auto headerText = new wxStaticText(dialog, wxID_ANY, header);
|
||||||
|
headerText->SetFont(wxFont(wxFontInfo().Bold()));
|
||||||
headerLayout->Add(headerText, wxSizerFlags().Align(wxALIGN_CENTER_VERTICAL));
|
headerLayout->Add(headerText, wxSizerFlags().Align(wxALIGN_CENTER_VERTICAL));
|
||||||
|
|
||||||
|
mainLayout->Add(headerLayout, wxSizerFlags().Border(wxALL));
|
||||||
|
if (onSend != nullptr)
|
||||||
|
{
|
||||||
|
mainLayout->AddSpacer(5);
|
||||||
|
mainLayout->Add(new wxStaticText(dialog, wxID_ANY, _("Click \"Send\" to submit the report to Audacity. This information is collected anonymously.")), wxSizerFlags().Border(wxALL));
|
||||||
|
}
|
||||||
|
mainLayout->AddSpacer(10);
|
||||||
|
mainLayout->Add(new wxStaticText(dialog, wxID_ANY, _("Problem details")), wxSizerFlags().Border(wxALL));
|
||||||
|
|
||||||
|
auto dumpTextCtrl = new wxTextCtrl(dialog, wxID_ANY, dump, wxDefaultPosition, wxSize(500, 300), wxTE_RICH | wxTE_READONLY | wxTE_MULTILINE | wxTE_DONTWRAP);
|
||||||
|
dumpTextCtrl->SetFont(wxFont(wxFontInfo().Family(wxFONTFAMILY_TELETYPE)));
|
||||||
|
dumpTextCtrl->ShowPosition(0);//scroll to top
|
||||||
|
mainLayout->Add(dumpTextCtrl, wxSizerFlags().Border(wxALL).Expand());
|
||||||
|
|
||||||
auto buttonsLayout = new wxBoxSizer(wxHORIZONTAL);
|
auto buttonsLayout = new wxBoxSizer(wxHORIZONTAL);
|
||||||
|
|
||||||
wxTextCtrl* commentCtrl = nullptr;
|
wxTextCtrl* commentCtrl = nullptr;
|
||||||
if (onSend != nullptr)
|
if (onSend != nullptr)
|
||||||
{
|
{
|
||||||
commentCtrl = new wxTextCtrl(frame, wxID_ANY, wxEmptyString, wxDefaultPosition, wxSize(500, 100), wxTE_MULTILINE);
|
mainLayout->AddSpacer(10);
|
||||||
|
mainLayout->Add(new wxStaticText(dialog, wxID_ANY, _("Comments")), wxSizerFlags().Border(wxALL));
|
||||||
|
|
||||||
|
commentCtrl = new wxTextCtrl(dialog, wxID_ANY, wxEmptyString, wxDefaultPosition, wxSize(500, 100), wxTE_MULTILINE);
|
||||||
commentCtrl->SetMaxLength(MaxUserCommentLength);
|
commentCtrl->SetMaxLength(MaxUserCommentLength);
|
||||||
|
|
||||||
|
mainLayout->Add(commentCtrl, wxSizerFlags().Border(wxALL).Expand());
|
||||||
}
|
}
|
||||||
|
|
||||||
if (onSend != nullptr)
|
if (onSend != nullptr && commentCtrl != nullptr)
|
||||||
{
|
{
|
||||||
auto okButton = new wxButton(frame, wxID_ANY, XC("&Don't send", "crash reporter button"));
|
auto dontSendButton = new wxButton(dialog, wxID_ANY, XC("&Don't send", "crash reporter button"));
|
||||||
auto sendButton = new wxButton(frame, wxID_ANY, XC("&Send", "crash reporter button"));
|
auto sendButton = new wxButton(dialog, wxID_ANY, XC("&Send", "crash reporter button"));
|
||||||
|
|
||||||
okButton->Bind(wxEVT_BUTTON, [frame](wxCommandEvent&)
|
dontSendButton->Bind(wxEVT_BUTTON, [dialog](wxCommandEvent&)
|
||||||
{
|
{
|
||||||
frame->Close(true);
|
dialog->Close(true);
|
||||||
});
|
});
|
||||||
sendButton->Bind(wxEVT_BUTTON, [frame, commentCtrl, onSend](wxCommandEvent&)
|
sendButton->Bind(wxEVT_BUTTON, [dialog, commentCtrl, onSend](wxCommandEvent&)
|
||||||
{
|
{
|
||||||
if (onSend(commentCtrl->GetValue()))
|
if (onSend(commentCtrl->GetValue()))
|
||||||
{
|
{
|
||||||
frame->Close(true);
|
dialog->Close(true);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
buttonsLayout->Add(okButton);
|
buttonsLayout->Add(dontSendButton);
|
||||||
buttonsLayout->AddSpacer(5);
|
buttonsLayout->AddSpacer(5);
|
||||||
buttonsLayout->Add(sendButton);
|
buttonsLayout->Add(sendButton);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
auto okButton = new wxButton(frame, wxID_OK, wxT("OK"));
|
auto okButton = new wxButton(dialog, wxID_OK, wxT("OK"));
|
||||||
okButton->Bind(wxEVT_BUTTON, [frame](wxCommandEvent&)
|
okButton->Bind(wxEVT_BUTTON, [dialog](wxCommandEvent&)
|
||||||
{
|
{
|
||||||
frame->Close(true);
|
dialog->Close(true);
|
||||||
});
|
});
|
||||||
buttonsLayout->Add(okButton);
|
buttonsLayout->Add(okButton);
|
||||||
}
|
}
|
||||||
|
|
||||||
mainLayout->Add(headerLayout, wxSizerFlags().Border(wxALL));
|
|
||||||
if (onSend != nullptr)
|
|
||||||
{
|
|
||||||
mainLayout->AddSpacer(5);
|
|
||||||
mainLayout->Add(new wxStaticText(frame, wxID_ANY, _("Click \"Send\" to submit the report to Audacity. This information is collected anonymously.")), wxSizerFlags().Border(wxALL));
|
|
||||||
}
|
|
||||||
mainLayout->AddSpacer(10);
|
|
||||||
mainLayout->Add(new wxStaticText(frame, wxID_ANY, _("Problem details")), wxSizerFlags().Border(wxALL));
|
|
||||||
|
|
||||||
auto dumpTextCtrl = new wxTextCtrl(frame, wxID_ANY, dump, wxDefaultPosition, wxSize(500, 300), wxTE_RICH | wxTE_READONLY | wxTE_MULTILINE | wxTE_DONTWRAP);
|
|
||||||
dumpTextCtrl->SetFont(wxFont(wxFontInfo().Family(wxFONTFAMILY_TELETYPE)));
|
|
||||||
dumpTextCtrl->ShowPosition(0);//scroll to top
|
|
||||||
mainLayout->Add(dumpTextCtrl, wxSizerFlags().Border(wxALL).Expand());
|
|
||||||
|
|
||||||
if (onSend != nullptr)
|
|
||||||
{
|
|
||||||
mainLayout->AddSpacer(10);
|
|
||||||
mainLayout->Add(new wxStaticText(frame, wxID_ANY, _("Comments")), wxSizerFlags().Border(wxALL));
|
|
||||||
mainLayout->Add(commentCtrl, wxSizerFlags().Border(wxALL).Expand());
|
|
||||||
}
|
|
||||||
|
|
||||||
mainLayout->Add(buttonsLayout, wxSizerFlags().Border(wxALL).Align(wxALIGN_RIGHT));
|
mainLayout->Add(buttonsLayout, wxSizerFlags().Border(wxALL).Align(wxALIGN_RIGHT));
|
||||||
frame->SetSizerAndFit(mainLayout);
|
dialog->SetSizerAndFit(mainLayout);
|
||||||
|
|
||||||
frame->Show(true);
|
dialog->Bind(wxEVT_CLOSE_WINDOW, [dialog](wxCloseEvent&) {
|
||||||
|
dialog->Destroy();
|
||||||
|
});
|
||||||
|
|
||||||
|
dialog->Show(true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -386,7 +392,6 @@ void CrashReportApp::OnInitCmdLine(wxCmdLineParser& parser)
|
|||||||
{
|
{
|
||||||
static const wxCmdLineEntryDesc cmdLineEntryDesc[] =
|
static const wxCmdLineEntryDesc cmdLineEntryDesc[] =
|
||||||
{
|
{
|
||||||
{ wxCMD_LINE_SWITCH, "h", "help", "Display help on the command line parameters", wxCMD_LINE_VAL_NONE, wxCMD_LINE_OPTION_HELP },
|
|
||||||
{ wxCMD_LINE_SWITCH, "s", "silent", "Send without displaying the confirmation dialog" },
|
{ wxCMD_LINE_SWITCH, "s", "silent", "Send without displaying the confirmation dialog" },
|
||||||
{ wxCMD_LINE_OPTION, "u", "url", "Crash report server URL", wxCMD_LINE_VAL_STRING, wxCMD_LINE_PARAM_OPTIONAL },
|
{ wxCMD_LINE_OPTION, "u", "url", "Crash report server URL", wxCMD_LINE_VAL_STRING, wxCMD_LINE_PARAM_OPTIONAL },
|
||||||
{ wxCMD_LINE_OPTION, "a", "args", "A set of arguments to send", wxCMD_LINE_VAL_STRING, wxCMD_LINE_PARAM_OPTIONAL },
|
{ wxCMD_LINE_OPTION, "a", "args", "A set of arguments to send", wxCMD_LINE_VAL_STRING, wxCMD_LINE_PARAM_OPTIONAL },
|
||||||
|
@ -45,8 +45,12 @@ if( ${_OPT}package_manual )
|
|||||||
) \
|
) \
|
||||||
")
|
")
|
||||||
|
|
||||||
|
if( "${CMAKE_GENERATOR}" MATCHES "Xcode" )
|
||||||
|
install( DIRECTORY "${out_dir}/${host}/" DESTINATION "${_APPDIR}/help/manual" )
|
||||||
|
elseif( "${CMAKE_GENERATOR}" MATCHES "Visual Studio*" )
|
||||||
install( DIRECTORY "${out_dir}/${host}/" DESTINATION "help/manual" )
|
install( DIRECTORY "${out_dir}/${host}/" DESTINATION "help/manual" )
|
||||||
endif()
|
endif()
|
||||||
|
endif()
|
||||||
|
|
||||||
if( NOT CMAKE_SYSTEM_NAME MATCHES "Darwin" )
|
if( NOT CMAKE_SYSTEM_NAME MATCHES "Darwin" )
|
||||||
if( NOT "${CMAKE_GENERATOR}" MATCHES "Visual Studio*")
|
if( NOT "${CMAKE_GENERATOR}" MATCHES "Visual Studio*")
|
||||||
|
@ -4822,7 +4822,7 @@ msgstr "Herzlich Willkommen zu Audacity-Version %s"
|
|||||||
#: src/ProjectManager.cpp
|
#: src/ProjectManager.cpp
|
||||||
#, c-format
|
#, c-format
|
||||||
msgid "%sSave changes to %s?"
|
msgid "%sSave changes to %s?"
|
||||||
msgstr "%sÄnderungen speichern nach %s?"
|
msgstr "%sÄnderungen an %s speichern?"
|
||||||
|
|
||||||
#: src/ProjectManager.cpp
|
#: src/ProjectManager.cpp
|
||||||
msgid "Save project before closing?"
|
msgid "Save project before closing?"
|
||||||
|
@ -22,17 +22,22 @@ fi
|
|||||||
cmake --build build -j "${cpus}" --config "${AUDACITY_BUILD_TYPE}"
|
cmake --build build -j "${cpus}" --config "${AUDACITY_BUILD_TYPE}"
|
||||||
|
|
||||||
BIN_OUTPUT_DIR=build/bin/${AUDACITY_BUILD_TYPE}
|
BIN_OUTPUT_DIR=build/bin/${AUDACITY_BUILD_TYPE}
|
||||||
|
SHARED_OUTPUT_DIR=build/shared/${AUDACITY_BUILD_TYPE}
|
||||||
SYMBOLS_OUTPUT_DIR=debug
|
SYMBOLS_OUTPUT_DIR=debug
|
||||||
|
|
||||||
mkdir ${SYMBOLS_OUTPUT_DIR}
|
mkdir ${SYMBOLS_OUTPUT_DIR}
|
||||||
|
|
||||||
if [[ "${OSTYPE}" == msys* ]]; then # Windows
|
if [[ "${OSTYPE}" == msys* ]]; then # Windows
|
||||||
# copy PDBs to debug folder...
|
# copy PDBs to debug folder...
|
||||||
find ${BIN_OUTPUT_DIR} -name '*.pdb' | xargs -I % cp % ${SYMBOLS_OUTPUT_DIR}
|
find ${BIN_OUTPUT_DIR} -name '*.pdb' | xargs -I % cp -v % ${SYMBOLS_OUTPUT_DIR}
|
||||||
|
find ${SHARED_OUTPUT_DIR} -name '*.pdb' | xargs -I % cp -v % ${SYMBOLS_OUTPUT_DIR}
|
||||||
|
find $(cygpath ${CONAN_USER_HOME}) -name '*.pdb' | xargs -I % cp -v % ${SYMBOLS_OUTPUT_DIR}
|
||||||
# and remove debug symbol files from the file tree before archieving
|
# and remove debug symbol files from the file tree before archieving
|
||||||
find ${BIN_OUTPUT_DIR} -name '*.iobj' -o -name '*.ipdb' -o -name '*.pdb' -o -name '*.ilk' | xargs rm -f
|
find ${BIN_OUTPUT_DIR} -name '*.iobj' -o -name '*.ipdb' -o -name '*.pdb' -o -name '*.ilk' | xargs rm -f
|
||||||
elif [[ "${OSTYPE}" == darwin* ]]; then # macOS
|
elif [[ "${OSTYPE}" == darwin* ]]; then # macOS
|
||||||
find ${BIN_OUTPUT_DIR} -name '*.dSYM' | xargs -J % mv % ${SYMBOLS_OUTPUT_DIR}
|
find ${BIN_OUTPUT_DIR} -name '*.dSYM' | xargs -J % mv % ${SYMBOLS_OUTPUT_DIR}
|
||||||
|
find ${SHARED_OUTPUT_DIR} -name '*.dSYM' | xargs -J % mv % ${SYMBOLS_OUTPUT_DIR}
|
||||||
|
find ${CONAN_USER_HOME}/dsyms -name '*.dSYM' | xargs -J % cp -R % ${SYMBOLS_OUTPUT_DIR}
|
||||||
else # Linux & others
|
else # Linux & others
|
||||||
chmod +x scripts/ci/linux/split_debug_symbols.sh
|
chmod +x scripts/ci/linux/split_debug_symbols.sh
|
||||||
find ${BIN_OUTPUT_DIR} -type f -executable -o -name '*.so' | xargs -n 1 scripts/ci/linux/split_debug_symbols.sh
|
find ${BIN_OUTPUT_DIR} -type f -executable -o -name '*.so' | xargs -n 1 scripts/ci/linux/split_debug_symbols.sh
|
||||||
|
@ -58,11 +58,32 @@ fi
|
|||||||
if [[ ${GIT_BRANCH} == release* ]]; then
|
if [[ ${GIT_BRANCH} == release* ]]; then
|
||||||
cmake_args+=(
|
cmake_args+=(
|
||||||
-D audacity_package_manual=yes
|
-D audacity_package_manual=yes
|
||||||
|
-D AUDACITY_BUILD_LEVEL=2
|
||||||
)
|
)
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Configure Audacity
|
# Configure Audacity
|
||||||
cmake "${cmake_args[@]}"
|
cmake "${cmake_args[@]}"
|
||||||
|
|
||||||
|
if [[ "${OSTYPE}" == msys* ]]; then # Windows
|
||||||
|
# On Windows, preserve PDB files before clearing the build cache
|
||||||
|
|
||||||
|
conanUnixPath=$(cygpath ${CONAN_USER_HOME})
|
||||||
|
pdbOutputPath="${conanUnixPath}/pdbs"
|
||||||
|
|
||||||
|
ls -la ${conanUnixPath}
|
||||||
|
|
||||||
|
mkdir -p "${pdbOutputPath}"
|
||||||
|
find "${conanUnixPath}/.conan" -name '*.pdb' '!' -name "vc14?.pdb" -type f | xargs -I % cp -v % ${pdbOutputPath}
|
||||||
|
elif [[ "${OSTYPE}" == darwin* ]]; then # macOS
|
||||||
|
# On macOS - find all the .dylib files and generate dSYMs from them
|
||||||
|
# in the same folder.
|
||||||
|
# dsymutil requires *.o files, so we need to generate files before clearing
|
||||||
|
# the build directories.
|
||||||
|
|
||||||
|
chmod +x scripts/ci/macos/generate_dsym.sh
|
||||||
|
scripts/ci/macos/generate_dsym.sh
|
||||||
|
fi
|
||||||
|
|
||||||
# Remove build directories and sources to reduce the cache size.
|
# Remove build directories and sources to reduce the cache size.
|
||||||
conan remove "*" --src --builds --force
|
conan remove "*" --src --builds --force
|
||||||
|
25
scripts/ci/macos/generate_dsym.sh
Normal file
25
scripts/ci/macos/generate_dsym.sh
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
|
||||||
|
set -xe
|
||||||
|
|
||||||
|
function extractDSym()
|
||||||
|
{
|
||||||
|
local lib=$1
|
||||||
|
local libfile=$(basename $lib)
|
||||||
|
local libname="${libfile%.*}"
|
||||||
|
local targetdir=$2
|
||||||
|
local dsymfile=${targetdir}/${libname}.dSYM
|
||||||
|
|
||||||
|
if [[ -d "$dsymfile" ]]; then
|
||||||
|
echo "Skipping dSYM generation for $libfile: dSYM exists"
|
||||||
|
elif [[ ! -L "$lib" && "$lib" != "{}" && $lib != *"dSYM"* ]]; then
|
||||||
|
echo "Extracting dSYMs from $libfile to $dsymfile"
|
||||||
|
dsymutil "$lib" -o "$dsymfile"
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
export -f extractDSym
|
||||||
|
|
||||||
|
mkdir -p "$CONAN_USER_HOME/dsyms"
|
||||||
|
|
||||||
|
find $CONAN_USER_HOME -name "*.dylib" | xargs -I {} bash -c "extractDSym \"{}\" \"$CONAN_USER_HOME/dsyms\""
|
@ -6,10 +6,10 @@ set -euxo pipefail
|
|||||||
|
|
||||||
cd build
|
cd build
|
||||||
|
|
||||||
|
cpack -C "${AUDACITY_BUILD_TYPE}" --verbose
|
||||||
|
|
||||||
if [[ "${OSTYPE}" == msys* && ${GIT_BRANCH} == release* ]]; then # Windows
|
if [[ "${OSTYPE}" == msys* && ${GIT_BRANCH} == release* ]]; then # Windows
|
||||||
cmake --build . --target innosetup --config "${AUDACITY_BUILD_TYPE}"
|
cmake --build . --target innosetup --config "${AUDACITY_BUILD_TYPE}"
|
||||||
else
|
|
||||||
cpack -C "${AUDACITY_BUILD_TYPE}" --verbose
|
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Remove the temporary directory
|
# Remove the temporary directory
|
||||||
|
@ -11,6 +11,6 @@ curl -sL https://sentry.io/get-cli/ | bash
|
|||||||
|
|
||||||
SYMBOLS=$(find debug | xargs)
|
SYMBOLS=$(find debug | xargs)
|
||||||
|
|
||||||
${INSTALL_DIR}/sentry-cli --auth-token ${SENTRY_AUTH_TOKEN} --url ${SENTRY_HOST} upload-dif \
|
${INSTALL_DIR}/sentry-cli --auth-token ${SENTRY_AUTH_TOKEN} --url https://${SENTRY_HOST} upload-dif \
|
||||||
--org ${SENTRY_ORG_SLUG} \
|
--org ${SENTRY_ORG_SLUG} \
|
||||||
--project ${SENTRY_PROJECT_SLUG} ${SYMBOLS}
|
--project ${SENTRY_PROJECT_SLUG} ${SYMBOLS}
|
||||||
|
@ -714,7 +714,7 @@ void AColor::PreComputeGradient() {
|
|||||||
gradient_pre[selected][1][i][2] = (unsigned char) (255 * b);
|
gradient_pre[selected][1][i][2] = (unsigned char) (255 * b);
|
||||||
}
|
}
|
||||||
|
|
||||||
// colorScheme 2: Grayscale
|
// colorScheme 3: Inverse Grayscale
|
||||||
for (int i = 0; i < gradientSteps; i++) {
|
for (int i = 0; i < gradientSteps; i++) {
|
||||||
float r, g, b;
|
float r, g, b;
|
||||||
float value = float(i) / gradientSteps;
|
float value = float(i) / gradientSteps;
|
||||||
@ -743,12 +743,12 @@ void AColor::PreComputeGradient() {
|
|||||||
b = 1.0f;
|
b = 1.0f;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
gradient_pre[selected][2][i][0] = (unsigned char)(255 * r);
|
gradient_pre[selected][3][i][0] = (unsigned char)(255 * r);
|
||||||
gradient_pre[selected][2][i][1] = (unsigned char)(255 * g);
|
gradient_pre[selected][3][i][1] = (unsigned char)(255 * g);
|
||||||
gradient_pre[selected][2][i][2] = (unsigned char)(255 * b);
|
gradient_pre[selected][3][i][2] = (unsigned char)(255 * b);
|
||||||
}
|
}
|
||||||
|
|
||||||
// colorScheme 3: Inv. Grayscale (=Old grayscale)
|
// colorScheme 2: Grayscale (=Old grayscale)
|
||||||
for (int i = 0; i<gradientSteps; i++) {
|
for (int i = 0; i<gradientSteps; i++) {
|
||||||
float r, g, b;
|
float r, g, b;
|
||||||
float value = float(i)/gradientSteps;
|
float value = float(i)/gradientSteps;
|
||||||
@ -781,9 +781,9 @@ void AColor::PreComputeGradient() {
|
|||||||
b = 1.0f;
|
b = 1.0f;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
gradient_pre[selected][3][i][0] = (unsigned char) (255 * r);
|
gradient_pre[selected][2][i][0] = (unsigned char) (255 * r);
|
||||||
gradient_pre[selected][3][i][1] = (unsigned char) (255 * g);
|
gradient_pre[selected][2][i][1] = (unsigned char) (255 * g);
|
||||||
gradient_pre[selected][3][i][2] = (unsigned char) (255 * b);
|
gradient_pre[selected][2][i][2] = (unsigned char) (255 * b);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -74,6 +74,10 @@ hold information about one contributor to Audacity.
|
|||||||
#define REV_IDENT (XO("No revision identifier was provided").Translation())
|
#define REV_IDENT (XO("No revision identifier was provided").Translation())
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#if defined(HAS_SENTRY_REPORTING) || defined(HAVE_UPDATES_CHECK) || defined(USE_BREAKPAD)
|
||||||
|
#define HAS_PRIVACY_POLICY
|
||||||
|
#endif
|
||||||
|
|
||||||
// To substitute into many other translatable strings
|
// To substitute into many other translatable strings
|
||||||
static const auto ProgramName =
|
static const auto ProgramName =
|
||||||
//XO("Audacity");
|
//XO("Audacity");
|
||||||
@ -129,7 +133,11 @@ void AboutDialog::CreateCreditsList()
|
|||||||
|
|
||||||
// The Audacity Team: developers and support
|
// The Audacity Team: developers and support
|
||||||
AddCredit(wxT("Anton Gerasimov"), developerFormat, roleTeamMember);
|
AddCredit(wxT("Anton Gerasimov"), developerFormat, roleTeamMember);
|
||||||
|
AddCredit(wxT("Jouni Helminen"), roleTeamMember);
|
||||||
|
AddCredit(wxT("Peter Jonas"), developerFormat, roleTeamMember);
|
||||||
|
AddCredit(wxT("Martin Keary"), roleTeamMember);
|
||||||
AddCredit(wxT("Paul Licameli"), developerFormat, roleTeamMember);
|
AddCredit(wxT("Paul Licameli"), developerFormat, roleTeamMember);
|
||||||
|
AddCredit(wxT("Anita Sudan"), roleTeamMember);
|
||||||
AddCredit(wxT("Vitaly Sverchinsky"), developerFormat, roleTeamMember);
|
AddCredit(wxT("Vitaly Sverchinsky"), developerFormat, roleTeamMember);
|
||||||
AddCredit(wxT("Dmitry Vedenko"), developerFormat, roleTeamMember);
|
AddCredit(wxT("Dmitry Vedenko"), developerFormat, roleTeamMember);
|
||||||
|
|
||||||
@ -825,7 +833,11 @@ void AboutDialog::PopulateInformationPage( ShuttleGui & S )
|
|||||||
|
|
||||||
void AboutDialog::PopulateLicensePage( ShuttleGui & S )
|
void AboutDialog::PopulateLicensePage( ShuttleGui & S )
|
||||||
{
|
{
|
||||||
|
#if defined(HAS_PRIVACY_POLICY)
|
||||||
|
S.StartNotebookPage(XC("Legal", "about dialog"));
|
||||||
|
#else
|
||||||
S.StartNotebookPage(XO("GPL License"));
|
S.StartNotebookPage(XO("GPL License"));
|
||||||
|
#endif
|
||||||
S.StartVerticalLay(1);
|
S.StartVerticalLay(1);
|
||||||
HtmlWindow *html = safenew LinkingHtmlWindow(S.GetParent(), -1,
|
HtmlWindow *html = safenew LinkingHtmlWindow(S.GetParent(), -1,
|
||||||
wxDefaultPosition,
|
wxDefaultPosition,
|
||||||
@ -838,7 +850,9 @@ void AboutDialog::PopulateLicensePage( ShuttleGui & S )
|
|||||||
// better proportionally spaced.
|
// better proportionally spaced.
|
||||||
//
|
//
|
||||||
// The GPL is not to be translated....
|
// The GPL is not to be translated....
|
||||||
wxString PageText= FormatHtmlText(
|
|
||||||
|
|
||||||
|
constexpr auto GPL_TEXT =
|
||||||
wxT(" <center>GNU GENERAL PUBLIC LICENSE\n</center>")
|
wxT(" <center>GNU GENERAL PUBLIC LICENSE\n</center>")
|
||||||
wxT(" <center>Version 2, June 1991\n</center>")
|
wxT(" <center>Version 2, June 1991\n</center>")
|
||||||
wxT("<p><p>")
|
wxT("<p><p>")
|
||||||
@ -1120,7 +1134,37 @@ wxT("OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED\n
|
|||||||
wxT("TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY\n")
|
wxT("TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY\n")
|
||||||
wxT("YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER\n")
|
wxT("YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER\n")
|
||||||
wxT("PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE\n")
|
wxT("PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE\n")
|
||||||
wxT("POSSIBILITY OF SUCH DAMAGES.\n"));
|
wxT("POSSIBILITY OF SUCH DAMAGES.\n");
|
||||||
|
|
||||||
|
#if defined(HAS_PRIVACY_POLICY)
|
||||||
|
/* i18n-hint: For "About Audacity...": Title for Privacy Policy section */
|
||||||
|
const auto privacyPolicyTitle = XC("PRIVACY POLICY", "about dialog");
|
||||||
|
|
||||||
|
/* i18n-hint: For "About Audacity...": Title of hyperlink to the privacy policy. This is an object of "See". */
|
||||||
|
const auto privacyPolicyURLText = XO("our Privacy Policy");
|
||||||
|
|
||||||
|
/* i18n-hint: %s will be replaced with "our Privacy Policy" */
|
||||||
|
const auto privacyPolicyText = XO(
|
||||||
|
"App update checking and error reporting require network access. "
|
||||||
|
"These features are optional. See %s "
|
||||||
|
"for more information.")
|
||||||
|
.Format(
|
||||||
|
Verbatim(
|
||||||
|
"[[https://www.audacityteam.org/about/desktop-privacy-notice/|%s]]")
|
||||||
|
.Format(privacyPolicyURLText));
|
||||||
|
|
||||||
|
const wxString privacyPolicyHTML = wxString(
|
||||||
|
wxT("<center>") +
|
||||||
|
privacyPolicyTitle.Translation() +
|
||||||
|
wxT("</center><p>") +
|
||||||
|
privacyPolicyText.Translation() +
|
||||||
|
wxT("</p><br/><br/>")
|
||||||
|
);
|
||||||
|
|
||||||
|
wxString PageText = FormatHtmlText(privacyPolicyHTML + GPL_TEXT);
|
||||||
|
#else
|
||||||
|
wxString PageText = FormatHtmlText(GPL_TEXT);
|
||||||
|
#endif
|
||||||
|
|
||||||
html->SetPage( PageText );
|
html->SetPage( PageText );
|
||||||
|
|
||||||
|
@ -241,7 +241,7 @@ void PopulatePreferences()
|
|||||||
wxYES_NO, NULL);
|
wxYES_NO, NULL);
|
||||||
if (action == wxYES) // reset
|
if (action == wxYES) // reset
|
||||||
{
|
{
|
||||||
gPrefs->DeleteAll();
|
ResetPreferences();
|
||||||
writeLang = true;
|
writeLang = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1823,6 +1823,44 @@ int AudioIO::StartStream(const TransportTracks &tracks,
|
|||||||
return mStreamToken;
|
return mStreamToken;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void AudioIO::DelayActions(bool recording)
|
||||||
|
{
|
||||||
|
mDelayingActions = recording;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool AudioIO::DelayingActions() const
|
||||||
|
{
|
||||||
|
return mDelayingActions || (mPortStreamV19 && mNumCaptureChannels > 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
void AudioIO::CallAfterRecording(PostRecordingAction action)
|
||||||
|
{
|
||||||
|
if (!action)
|
||||||
|
return;
|
||||||
|
|
||||||
|
{
|
||||||
|
std::lock_guard<std::mutex> guard{ mPostRecordingActionMutex };
|
||||||
|
if (mPostRecordingAction) {
|
||||||
|
// Enqueue it, even if perhaps not still recording,
|
||||||
|
// but it wasn't cleared yet
|
||||||
|
mPostRecordingAction = [
|
||||||
|
prevAction = std::move(mPostRecordingAction),
|
||||||
|
nextAction = std::move(action)
|
||||||
|
]{ prevAction(); nextAction(); };
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
else if (DelayingActions()) {
|
||||||
|
mPostRecordingAction = std::move(action);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Don't delay it except until idle time.
|
||||||
|
// (Recording might start between now and then, but won't go far before
|
||||||
|
// the action is done. So the system isn't bulletproof yet.)
|
||||||
|
wxTheApp->CallAfter(std::move(action));
|
||||||
|
}
|
||||||
|
|
||||||
bool AudioIO::AllocateBuffers(
|
bool AudioIO::AllocateBuffers(
|
||||||
const AudioIOStartStreamOptions &options,
|
const AudioIOStartStreamOptions &options,
|
||||||
const TransportTracks &tracks, double t0, double t1, double sampleRate,
|
const TransportTracks &tracks, double t0, double t1, double sampleRate,
|
||||||
@ -2416,6 +2454,21 @@ void AudioIO::StopStream()
|
|||||||
if (pListener && mNumCaptureChannels > 0)
|
if (pListener && mNumCaptureChannels > 0)
|
||||||
pListener->OnAudioIOStopRecording();
|
pListener->OnAudioIOStopRecording();
|
||||||
|
|
||||||
|
wxTheApp->CallAfter([this]{
|
||||||
|
if (mPortStreamV19 && mNumCaptureChannels > 0)
|
||||||
|
// Recording was restarted between StopStream and idle time
|
||||||
|
// So the actions can keep waiting
|
||||||
|
return;
|
||||||
|
// In case some other thread was waiting on the mutex too:
|
||||||
|
std::this_thread::yield();
|
||||||
|
std::lock_guard<std::mutex> guard{ mPostRecordingActionMutex };
|
||||||
|
if (mPostRecordingAction) {
|
||||||
|
mPostRecordingAction();
|
||||||
|
mPostRecordingAction = {};
|
||||||
|
}
|
||||||
|
DelayActions(false);
|
||||||
|
});
|
||||||
|
|
||||||
//
|
//
|
||||||
// Only set token to 0 after we're totally finished with everything
|
// Only set token to 0 after we're totally finished with everything
|
||||||
//
|
//
|
||||||
|
@ -18,9 +18,9 @@
|
|||||||
#include "AudioIOBase.h" // to inherit
|
#include "AudioIOBase.h" // to inherit
|
||||||
#include "PlaybackSchedule.h" // member variable
|
#include "PlaybackSchedule.h" // member variable
|
||||||
|
|
||||||
|
#include <functional>
|
||||||
|
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
#include <mutex>
|
||||||
#include <utility>
|
#include <utility>
|
||||||
#include <wx/atomic.h> // member variable
|
#include <wx/atomic.h> // member variable
|
||||||
|
|
||||||
@ -621,6 +621,12 @@ public:
|
|||||||
* by the specified amount from where it is now */
|
* by the specified amount from where it is now */
|
||||||
void SeekStream(double seconds) { mSeek = seconds; }
|
void SeekStream(double seconds) { mSeek = seconds; }
|
||||||
|
|
||||||
|
using PostRecordingAction = std::function<void()>;
|
||||||
|
|
||||||
|
//! Enqueue action for main thread idle time, not before the end of any recording in progress
|
||||||
|
/*! This may be called from non-main threads */
|
||||||
|
void CallAfterRecording(PostRecordingAction action);
|
||||||
|
|
||||||
#ifdef EXPERIMENTAL_SCRUBBING_SUPPORT
|
#ifdef EXPERIMENTAL_SCRUBBING_SUPPORT
|
||||||
bool IsScrubbing() const { return IsBusy() && mScrubState != 0; }
|
bool IsScrubbing() const { return IsBusy() && mScrubState != 0; }
|
||||||
|
|
||||||
@ -733,15 +739,18 @@ public:
|
|||||||
static void Init();
|
static void Init();
|
||||||
static void Deinit();
|
static void Deinit();
|
||||||
|
|
||||||
|
/*! For purposes of CallAfterRecording, treat time from now as if
|
||||||
|
recording (when argument is true) or not necessarily so (false) */
|
||||||
|
void DelayActions(bool recording);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
|
bool DelayingActions() const;
|
||||||
|
|
||||||
/** \brief Set the current VU meters - this should be done once after
|
/** \brief Set the current VU meters - this should be done once after
|
||||||
* each call to StartStream currently */
|
* each call to StartStream currently */
|
||||||
void SetMeters();
|
void SetMeters();
|
||||||
|
|
||||||
|
|
||||||
/** \brief Opens the portaudio stream(s) used to do playback or recording
|
/** \brief Opens the portaudio stream(s) used to do playback or recording
|
||||||
* (or both) through.
|
* (or both) through.
|
||||||
*
|
*
|
||||||
@ -787,6 +796,10 @@ private:
|
|||||||
*
|
*
|
||||||
* If bOnlyBuffers is specified, it only cleans up the buffers. */
|
* If bOnlyBuffers is specified, it only cleans up the buffers. */
|
||||||
void StartStreamCleanup(bool bOnlyBuffers = false);
|
void StartStreamCleanup(bool bOnlyBuffers = false);
|
||||||
|
|
||||||
|
std::mutex mPostRecordingActionMutex;
|
||||||
|
PostRecordingAction mPostRecordingAction;
|
||||||
|
bool mDelayingActions{ false };
|
||||||
};
|
};
|
||||||
|
|
||||||
static constexpr unsigned ScrubPollInterval_ms = 50;
|
static constexpr unsigned ScrubPollInterval_ms = 50;
|
||||||
|
@ -1055,7 +1055,7 @@ list( APPEND DEFINES
|
|||||||
__STDC_CONSTANT_MACROS
|
__STDC_CONSTANT_MACROS
|
||||||
STRICT
|
STRICT
|
||||||
>
|
>
|
||||||
$<$<BOOL:${USE_UPDATE_CHECK}>:
|
$<$<BOOL:${${_OPT}has_updates_check}>:
|
||||||
HAVE_UPDATES_CHECK
|
HAVE_UPDATES_CHECK
|
||||||
>
|
>
|
||||||
)
|
)
|
||||||
@ -1375,6 +1375,7 @@ if( "${CMAKE_GENERATOR}" MATCHES "Xcode|Visual Studio*" )
|
|||||||
USE_SOURCE_PERMISSIONS
|
USE_SOURCE_PERMISSIONS
|
||||||
PATTERN "*.pdb" EXCLUDE
|
PATTERN "*.pdb" EXCLUDE
|
||||||
PATTERN "*.ilk" EXCLUDE
|
PATTERN "*.ilk" EXCLUDE
|
||||||
|
PATTERN "*.dSYM" EXCLUDE
|
||||||
)
|
)
|
||||||
else()
|
else()
|
||||||
if( CMAKE_SYSTEM_NAME MATCHES "Darwin" )
|
if( CMAKE_SYSTEM_NAME MATCHES "Darwin" )
|
||||||
|
@ -886,6 +886,9 @@ void PluginManager::Load()
|
|||||||
if (!registry.HasGroup(REGROOT))
|
if (!registry.HasGroup(REGROOT))
|
||||||
{
|
{
|
||||||
// Must start over
|
// Must start over
|
||||||
|
// This DeleteAll affects pluginregistry.cfg only, not audacity.cfg
|
||||||
|
// That is, the memory of on/off states of effect (and generator,
|
||||||
|
// analyzer, and tool) plug-ins
|
||||||
registry.DeleteAll();
|
registry.DeleteAll();
|
||||||
registry.Flush();
|
registry.Flush();
|
||||||
return;
|
return;
|
||||||
@ -1223,7 +1226,7 @@ void PluginManager::Save()
|
|||||||
{}, {}, FileNames::PluginRegistry());
|
{}, {}, FileNames::PluginRegistry());
|
||||||
auto ®istry = *pRegistry;
|
auto ®istry = *pRegistry;
|
||||||
|
|
||||||
// Clear it out
|
// Clear pluginregistry.cfg (not audacity.cfg)
|
||||||
registry.DeleteAll();
|
registry.DeleteAll();
|
||||||
|
|
||||||
// Write the version string
|
// Write the version string
|
||||||
|
@ -63,6 +63,9 @@
|
|||||||
#include "MemoryX.h"
|
#include "MemoryX.h"
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
|
||||||
|
BoolSetting DefaultUpdatesCheckingFlag{
|
||||||
|
L"/Update/DefaultUpdatesChecking", true };
|
||||||
|
|
||||||
std::unique_ptr<FileConfig> ugPrefs {};
|
std::unique_ptr<FileConfig> ugPrefs {};
|
||||||
|
|
||||||
FileConfig *gPrefs = nullptr;
|
FileConfig *gPrefs = nullptr;
|
||||||
@ -179,6 +182,25 @@ void InitPreferences( std::unique_ptr<FileConfig> uPrefs )
|
|||||||
wxConfigBase::Set(gPrefs);
|
wxConfigBase::Set(gPrefs);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ResetPreferences()
|
||||||
|
{
|
||||||
|
// Future: make this a static registry table, so the settings objects
|
||||||
|
// don't need to be defined in this source code file to avoid dependency
|
||||||
|
// cycles
|
||||||
|
std::pair<BoolSetting &, bool> stickyBoolSettings[] {
|
||||||
|
{DefaultUpdatesCheckingFlag, 0},
|
||||||
|
// ... others?
|
||||||
|
};
|
||||||
|
for (auto &pair : stickyBoolSettings)
|
||||||
|
pair.second = pair.first.Read();
|
||||||
|
|
||||||
|
bool savedValue = DefaultUpdatesCheckingFlag.Read();
|
||||||
|
gPrefs->DeleteAll();
|
||||||
|
|
||||||
|
for (auto &pair : stickyBoolSettings)
|
||||||
|
pair.first.Write(pair.second);
|
||||||
|
}
|
||||||
|
|
||||||
void FinishPreferences()
|
void FinishPreferences()
|
||||||
{
|
{
|
||||||
if (gPrefs) {
|
if (gPrefs) {
|
||||||
|
@ -48,6 +48,12 @@
|
|||||||
class wxFileName;
|
class wxFileName;
|
||||||
|
|
||||||
void InitPreferences( std::unique_ptr<FileConfig> uPrefs );
|
void InitPreferences( std::unique_ptr<FileConfig> uPrefs );
|
||||||
|
//! Call this to reset preferences to an (almost)-"new" default state
|
||||||
|
/*!
|
||||||
|
There is at least one exception to that: user preferences we want to make
|
||||||
|
more "sticky." Notably, whether automatic update checking is preferred.
|
||||||
|
*/
|
||||||
|
void ResetPreferences();
|
||||||
void FinishPreferences();
|
void FinishPreferences();
|
||||||
|
|
||||||
extern AUDACITY_DLL_API FileConfig *gPrefs;
|
extern AUDACITY_DLL_API FileConfig *gPrefs;
|
||||||
@ -423,4 +429,7 @@ struct AUDACITY_DLL_API PreferenceInitializer {
|
|||||||
static void ReinitializeAll();
|
static void ReinitializeAll();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Special extra-sticky settings
|
||||||
|
extern AUDACITY_DLL_API BoolSetting DefaultUpdatesCheckingFlag;
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -40,6 +40,7 @@
|
|||||||
#include <wx/timer.h>
|
#include <wx/timer.h>
|
||||||
#include <wx/dynlib.h> //<! For windows.h
|
#include <wx/dynlib.h> //<! For windows.h
|
||||||
|
|
||||||
|
#include "AudioIO.h"
|
||||||
#include "ShuttleGui.h"
|
#include "ShuttleGui.h"
|
||||||
#include "ProjectAudioManager.h"
|
#include "ProjectAudioManager.h"
|
||||||
#include "ProjectFileIO.h"
|
#include "ProjectFileIO.h"
|
||||||
@ -481,6 +482,11 @@ int TimerRecordDialog::RunWaitDialog()
|
|||||||
{
|
{
|
||||||
auto updateResult = ProgressResult::Success;
|
auto updateResult = ProgressResult::Success;
|
||||||
|
|
||||||
|
const auto gAudioIO = AudioIO::Get();
|
||||||
|
gAudioIO->DelayActions(true);
|
||||||
|
{
|
||||||
|
auto cleanup = finally([gAudioIO]{ gAudioIO->DelayActions(false); });
|
||||||
|
|
||||||
if (m_DateTime_Start > wxDateTime::UNow())
|
if (m_DateTime_Start > wxDateTime::UNow())
|
||||||
updateResult = this->WaitForStart();
|
updateResult = this->WaitForStart();
|
||||||
|
|
||||||
@ -535,6 +541,7 @@ int TimerRecordDialog::RunWaitDialog()
|
|||||||
bIsRecording = (wxDateTime::UNow() <= m_DateTime_End); // Call UNow() again for extra accuracy...
|
bIsRecording = (wxDateTime::UNow() <= m_DateTime_End); // Call UNow() again for extra accuracy...
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Must do this AFTER the timer project dialog has been deleted to ensure the application
|
// Must do this AFTER the timer project dialog has been deleted to ensure the application
|
||||||
// responds to the AUDIOIO events...see not about bug #334 in the ProgressDialog constructor.
|
// responds to the AUDIOIO events...see not about bug #334 in the ProgressDialog constructor.
|
||||||
|
@ -648,6 +648,7 @@ wxString EffectManager::GetPreset(const PluginID & ID, const wxString & params,
|
|||||||
return preset;
|
return preset;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// This cleans a config "file" backed by a string in memory.
|
||||||
eap.DeleteAll();
|
eap.DeleteAll();
|
||||||
|
|
||||||
eap.Write(wxT("Use Preset"), preset);
|
eap.Write(wxT("Use Preset"), preset);
|
||||||
|
@ -106,15 +106,38 @@
|
|||||||
|
|
||||||
return intgr ;
|
return intgr ;
|
||||||
}
|
}
|
||||||
#elif (defined (WIN32) || defined (_WIN32)) && defined(_M_3X64)
|
#elif (defined (WIN32) || defined (_WIN32)) && defined(_M_X64)
|
||||||
|
|
||||||
#include <math.h>
|
#include <math.h>
|
||||||
#include <immintrin.h>
|
#include <immintrin.h>
|
||||||
|
#include <emmintrin.h>
|
||||||
|
|
||||||
__inline long int
|
#ifdef _MSC_VER
|
||||||
lrintf (float flt)
|
#pragma function(lrint, lrintf)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
__inline
|
||||||
|
long int lrint(double flt)
|
||||||
{
|
{
|
||||||
return _mm_cvt_ss2si(_mm_set_ss(flt));
|
return _mm_cvtsd_si32(_mm_set_sd(flt));
|
||||||
|
}
|
||||||
|
|
||||||
|
__inline
|
||||||
|
long int lrintf (float flt)
|
||||||
|
{
|
||||||
|
return _mm_cvtss_si32(_mm_set_ss(flt));
|
||||||
|
}
|
||||||
|
|
||||||
|
__inline
|
||||||
|
long long int llrint(double flt)
|
||||||
|
{
|
||||||
|
return _mm_cvtsd_si64(_mm_set_sd(flt));
|
||||||
|
}
|
||||||
|
|
||||||
|
__inline
|
||||||
|
long long int llrintf(float flt)
|
||||||
|
{
|
||||||
|
return _mm_cvtss_si64(_mm_set_ss(flt));
|
||||||
}
|
}
|
||||||
|
|
||||||
#elif (HAVE_LRINT && HAVE_LRINTF)
|
#elif (HAVE_LRINT && HAVE_LRINTF)
|
||||||
|
@ -393,7 +393,7 @@ void OnResetConfig(const CommandContext &context)
|
|||||||
menuManager.mLastAnalyzer = "";
|
menuManager.mLastAnalyzer = "";
|
||||||
menuManager.mLastTool = "";
|
menuManager.mLastTool = "";
|
||||||
|
|
||||||
gPrefs->DeleteAll();
|
ResetPreferences();
|
||||||
|
|
||||||
// Directory will be reset on next restart.
|
// Directory will be reset on next restart.
|
||||||
FileNames::UpdateDefaultPath(FileNames::Operation::Temp, TempDirectory::DefaultTempDir());
|
FileNames::UpdateDefaultPath(FileNames::Operation::Temp, TempDirectory::DefaultTempDir());
|
||||||
|
@ -70,8 +70,7 @@ void ApplicationPrefs::PopulateOrExchange(ShuttleGui & S)
|
|||||||
|
|
||||||
S.StartStatic(XO("Update Audacity"));
|
S.StartStatic(XO("Update Audacity"));
|
||||||
{
|
{
|
||||||
S.TieCheckBox(XO("&Check for Updates"),
|
S.TieCheckBox(XO("&Check for Updates"), DefaultUpdatesCheckingFlag);
|
||||||
UpdatesCheckingSettings::DefaultUpdatesCheckingFlag);
|
|
||||||
}
|
}
|
||||||
S.EndStatic();
|
S.EndStatic();
|
||||||
S.EndScroller();
|
S.EndScroller();
|
||||||
|
@ -182,7 +182,7 @@ void SpectrogramSettings::ColorSchemeEnumSetting::Migrate(wxString &value)
|
|||||||
// Migrate old grayscale option to Color scheme choice
|
// Migrate old grayscale option to Color scheme choice
|
||||||
bool isGrayscale = (gPrefs->Read(wxT("/Spectrum/Grayscale"), 0L) != 0);
|
bool isGrayscale = (gPrefs->Read(wxT("/Spectrum/Grayscale"), 0L) != 0);
|
||||||
if (isGrayscale && !gPrefs->Read(wxT("/Spectrum/ColorScheme"), &value)) {
|
if (isGrayscale && !gPrefs->Read(wxT("/Spectrum/ColorScheme"), &value)) {
|
||||||
value = GetColorSchemeNames().at(csInvGrayscale).Internal();
|
value = GetColorSchemeNames().at(csGrayscale).Internal();
|
||||||
Write(value);
|
Write(value);
|
||||||
gPrefs->Flush();
|
gPrefs->Flush();
|
||||||
}
|
}
|
||||||
|
@ -56,23 +56,41 @@ bool UpdateDataParser::HandleXMLTag(const wxChar* tag, const wxChar** attrs)
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (wxStrcmp(tag, mXmlTagNames[XmlParsedTags::kWindowsTag]) == 0)
|
const wxPlatformInfo& info = wxPlatformInfo::Get();
|
||||||
|
|
||||||
|
constexpr bool is32Bit = sizeof(void*) == 4;
|
||||||
|
constexpr bool is64Bit = sizeof(void*) == 8;
|
||||||
|
|
||||||
|
if (is32Bit)
|
||||||
{
|
{
|
||||||
if (wxPlatformInfo::Get().GetOperatingSystemId() & wxOS_WINDOWS)
|
if (wxStrcmp(tag, mXmlTagNames[XmlParsedTags::kWin32Tag]) == 0)
|
||||||
|
{
|
||||||
|
if (info.GetOperatingSystemId() & wxOS_WINDOWS)
|
||||||
mXmlParsingState = XmlParsedTags::kOsTag;
|
mXmlParsingState = XmlParsedTags::kOsTag;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (is64Bit)
|
||||||
|
{
|
||||||
|
if (wxStrcmp(tag, mXmlTagNames[XmlParsedTags::kWin64Tag]) == 0)
|
||||||
|
{
|
||||||
|
if (info.GetOperatingSystemId() & wxOS_WINDOWS)
|
||||||
|
mXmlParsingState = XmlParsedTags::kOsTag;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (wxStrcmp(tag, mXmlTagNames[XmlParsedTags::kMacosTag]) == 0)
|
if (wxStrcmp(tag, mXmlTagNames[XmlParsedTags::kMacosTag]) == 0)
|
||||||
{
|
{
|
||||||
if (wxPlatformInfo::Get().GetOperatingSystemId() & wxOS_MAC)
|
if (info.GetOperatingSystemId() & wxOS_MAC)
|
||||||
mXmlParsingState = XmlParsedTags::kOsTag;
|
mXmlParsingState = XmlParsedTags::kOsTag;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (wxStrcmp(tag, mXmlTagNames[XmlParsedTags::kLinuxTag]) == 0)
|
if (wxStrcmp(tag, mXmlTagNames[XmlParsedTags::kLinuxTag]) == 0)
|
||||||
{
|
{
|
||||||
if (wxPlatformInfo::Get().GetOperatingSystemId() & wxOS_UNIX_LINUX)
|
if (info.GetOperatingSystemId() & wxOS_UNIX_LINUX)
|
||||||
mXmlParsingState = XmlParsedTags::kOsTag;
|
mXmlParsingState = XmlParsedTags::kOsTag;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -36,7 +36,8 @@ private:
|
|||||||
kUpdateTag,
|
kUpdateTag,
|
||||||
kDescriptionTag,
|
kDescriptionTag,
|
||||||
kOsTag,
|
kOsTag,
|
||||||
kWindowsTag,
|
kWin32Tag,
|
||||||
|
kWin64Tag,
|
||||||
kMacosTag,
|
kMacosTag,
|
||||||
kLinuxTag,
|
kLinuxTag,
|
||||||
kVersionTag,
|
kVersionTag,
|
||||||
@ -48,7 +49,8 @@ private:
|
|||||||
{ XmlParsedTags::kUpdateTag, wxT("Updates") },
|
{ XmlParsedTags::kUpdateTag, wxT("Updates") },
|
||||||
{ XmlParsedTags::kDescriptionTag, wxT("Description") },
|
{ XmlParsedTags::kDescriptionTag, wxT("Description") },
|
||||||
{ XmlParsedTags::kOsTag, wxT("OS") },
|
{ XmlParsedTags::kOsTag, wxT("OS") },
|
||||||
{ XmlParsedTags::kWindowsTag, wxT("Windows") },
|
{ XmlParsedTags::kWin32Tag, wxT("Win32") },
|
||||||
|
{ XmlParsedTags::kWin64Tag, wxT("Win64") },
|
||||||
{ XmlParsedTags::kMacosTag, wxT("Macos") },
|
{ XmlParsedTags::kMacosTag, wxT("Macos") },
|
||||||
{ XmlParsedTags::kLinuxTag, wxT("Linux") },
|
{ XmlParsedTags::kLinuxTag, wxT("Linux") },
|
||||||
{ XmlParsedTags::kVersionTag, wxT("Version") },
|
{ XmlParsedTags::kVersionTag, wxT("Version") },
|
||||||
|
@ -10,6 +10,7 @@
|
|||||||
#include "UpdateManager.h"
|
#include "UpdateManager.h"
|
||||||
#include "UpdatePopupDialog.h"
|
#include "UpdatePopupDialog.h"
|
||||||
|
|
||||||
|
#include "AudioIO.h"
|
||||||
#include "NetworkManager.h"
|
#include "NetworkManager.h"
|
||||||
#include "IResponse.h"
|
#include "IResponse.h"
|
||||||
#include "Request.h"
|
#include "Request.h"
|
||||||
@ -21,26 +22,23 @@
|
|||||||
#include <wx/frame.h>
|
#include <wx/frame.h>
|
||||||
|
|
||||||
#include <mutex>
|
#include <mutex>
|
||||||
|
#include <cstdint>
|
||||||
BoolSetting UpdatesCheckingSettings::DefaultUpdatesCheckingFlag{
|
|
||||||
L"/Update/DefaultUpdatesChecking", true };
|
|
||||||
|
|
||||||
static const char* prefsUpdateScheduledTime = "/Update/UpdateScheduledTime";
|
static const char* prefsUpdateScheduledTime = "/Update/UpdateScheduledTime";
|
||||||
|
|
||||||
|
|
||||||
|
using Clock = std::chrono::system_clock;
|
||||||
|
using TimePoint = Clock::time_point;
|
||||||
|
using Duration = TimePoint::duration;
|
||||||
|
|
||||||
|
constexpr Duration updatesCheckInterval = std::chrono::hours(12);
|
||||||
|
|
||||||
enum { ID_TIMER = wxID_HIGHEST + 1 };
|
enum { ID_TIMER = wxID_HIGHEST + 1 };
|
||||||
|
|
||||||
BEGIN_EVENT_TABLE(UpdateManager, wxEvtHandler)
|
BEGIN_EVENT_TABLE(UpdateManager, wxEvtHandler)
|
||||||
EVT_TIMER(ID_TIMER, UpdateManager::OnTimer)
|
EVT_TIMER(ID_TIMER, UpdateManager::OnTimer)
|
||||||
END_EVENT_TABLE()
|
END_EVENT_TABLE()
|
||||||
|
|
||||||
UpdateManager::UpdateManager()
|
|
||||||
: mUpdateCheckingInterval(
|
|
||||||
std::chrono::milliseconds(std::chrono::hours(12)).count())
|
|
||||||
{}
|
|
||||||
|
|
||||||
UpdateManager::~UpdateManager()
|
|
||||||
{}
|
|
||||||
|
|
||||||
UpdateManager& UpdateManager::GetInstance()
|
UpdateManager& UpdateManager::GetInstance()
|
||||||
{
|
{
|
||||||
static UpdateManager updateManager;
|
static UpdateManager updateManager;
|
||||||
@ -64,38 +62,48 @@ VersionPatch UpdateManager::GetVersionPatch() const
|
|||||||
return mVersionPatch;
|
return mVersionPatch;
|
||||||
}
|
}
|
||||||
|
|
||||||
void UpdateManager::GetUpdates()
|
void UpdateManager::GetUpdates(bool ignoreNetworkErrors)
|
||||||
{
|
{
|
||||||
const audacity::network_manager::Request request("https://updates.audacityteam.org/feed/latest.xml");
|
const audacity::network_manager::Request request("https://updates.audacityteam.org/feed/latest.xml");
|
||||||
auto response = audacity::network_manager::NetworkManager::GetInstance().doGet(request);
|
auto response = audacity::network_manager::NetworkManager::GetInstance().doGet(request);
|
||||||
|
|
||||||
response->setRequestFinishedCallback([response, this](audacity::network_manager::IResponse*) {
|
response->setRequestFinishedCallback([response, ignoreNetworkErrors, this](audacity::network_manager::IResponse*) {
|
||||||
|
|
||||||
|
auto gAudioIO = AudioIO::Get();
|
||||||
if (response->getError() != audacity::network_manager::NetworkError::NoError)
|
if (response->getError() != audacity::network_manager::NetworkError::NoError)
|
||||||
{
|
{
|
||||||
wxTheApp->CallAfter([] {ShowExceptionDialog(nullptr,
|
if (!ignoreNetworkErrors)
|
||||||
XC("Error checking for update", "update dialog"),
|
{
|
||||||
XC("Unable to connect to Audacity update server.", "update dialog"),
|
gAudioIO->CallAfterRecording([] {
|
||||||
|
ShowExceptionDialog(
|
||||||
|
nullptr, XC("Error checking for update", "update dialog"),
|
||||||
|
XC("Unable to connect to Audacity update server.",
|
||||||
|
"update dialog"),
|
||||||
wxString());
|
wxString());
|
||||||
});
|
});
|
||||||
|
}
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!mUpdateDataParser.Parse(response->readAll<VersionPatch::UpdateDataFormat>(), &mVersionPatch))
|
if (!mUpdateDataParser.Parse(response->readAll<VersionPatch::UpdateDataFormat>(), &mVersionPatch))
|
||||||
{
|
{
|
||||||
wxTheApp->CallAfter([] {ShowExceptionDialog(nullptr,
|
if (!ignoreNetworkErrors)
|
||||||
XC("Error checking for update", "update dialog"),
|
{
|
||||||
|
gAudioIO->CallAfterRecording([] {
|
||||||
|
ShowExceptionDialog(
|
||||||
|
nullptr, XC("Error checking for update", "update dialog"),
|
||||||
XC("Update data was corrupted.", "update dialog"),
|
XC("Update data was corrupted.", "update dialog"),
|
||||||
wxString());
|
wxString());
|
||||||
});
|
});
|
||||||
|
}
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (mVersionPatch.version > CurrentBuildVersion())
|
if (mVersionPatch.version > CurrentBuildVersion())
|
||||||
{
|
{
|
||||||
wxTheApp->CallAfter([this] {
|
gAudioIO->CallAfterRecording([this] {
|
||||||
UpdatePopupDialog dlg(nullptr, mVersionPatch);
|
UpdatePopupDialog dlg(nullptr, mVersionPatch);
|
||||||
const int code = dlg.ShowModal();
|
const int code = dlg.ShowModal();
|
||||||
|
|
||||||
@ -116,34 +124,49 @@ void UpdateManager::GetUpdates()
|
|||||||
|
|
||||||
void UpdateManager::OnTimer(wxTimerEvent& WXUNUSED(event))
|
void UpdateManager::OnTimer(wxTimerEvent& WXUNUSED(event))
|
||||||
{
|
{
|
||||||
bool updatesCheckingEnabled = UpdatesCheckingSettings::DefaultUpdatesCheckingFlag.Read();
|
bool updatesCheckingEnabled = DefaultUpdatesCheckingFlag.Read();
|
||||||
|
|
||||||
if (updatesCheckingEnabled && IsTimeForUpdatesChecking())
|
if (updatesCheckingEnabled && IsTimeForUpdatesChecking())
|
||||||
GetUpdates();
|
GetUpdates(true);
|
||||||
|
|
||||||
mTimer.StartOnce(mUpdateCheckingInterval);
|
mTimer.StartOnce(std::chrono::duration_cast<std::chrono::milliseconds>(
|
||||||
|
updatesCheckInterval)
|
||||||
|
.count());
|
||||||
}
|
}
|
||||||
|
|
||||||
bool UpdateManager::IsTimeForUpdatesChecking()
|
bool UpdateManager::IsTimeForUpdatesChecking()
|
||||||
{
|
{
|
||||||
long long nextUpdatesCheckingTime = std::stoll(
|
// We use atoll here, so there is no need to handle the exception,
|
||||||
gPrefs->Read(prefsUpdateScheduledTime, "0").ToStdString());
|
// if prefsUpdateScheduledTime is corrupted.
|
||||||
|
// atoll will return 0 on failure, which suits us well.
|
||||||
|
const TimePoint nextUpdatesCheckingTime(std::chrono::milliseconds(
|
||||||
|
atoll(gPrefs->Read(prefsUpdateScheduledTime, "0").c_str())));
|
||||||
|
|
||||||
// Get current time in milliseconds
|
// Get current time
|
||||||
auto now_ms = std::chrono::time_point_cast<std::chrono::milliseconds>(
|
const TimePoint currentTime = Clock::now();
|
||||||
std::chrono::system_clock::now());
|
|
||||||
|
|
||||||
auto currentTimeInMillisec = std::chrono::duration_cast<std::chrono::milliseconds>(
|
|
||||||
now_ms.time_since_epoch()).count();
|
|
||||||
|
|
||||||
// If next update time 0 or less then current time -> show update dialog,
|
// If next update time 0 or less then current time -> show update dialog,
|
||||||
// else this condition allow us to avoid from duplicating update notifications.
|
// else this condition allow us to avoid from duplicating update notifications.
|
||||||
if (nextUpdatesCheckingTime < currentTimeInMillisec)
|
if (nextUpdatesCheckingTime < currentTime)
|
||||||
{
|
{
|
||||||
nextUpdatesCheckingTime = currentTimeInMillisec + mUpdateCheckingInterval;
|
|
||||||
|
|
||||||
gPrefs->Write(prefsUpdateScheduledTime,
|
// Round down the nextUpdatesChecking time to a day.
|
||||||
wxString(std::to_string(nextUpdatesCheckingTime)));
|
// This is required to ensure, that update is
|
||||||
|
// checked daily
|
||||||
|
using DayDuration =
|
||||||
|
std::chrono::duration<int32_t, std::ratio<60 * 60 * 24>>;
|
||||||
|
|
||||||
|
const auto postponeUpdateUntil =
|
||||||
|
std::chrono::time_point_cast<DayDuration>(
|
||||||
|
currentTime) + DayDuration(1);
|
||||||
|
|
||||||
|
const std::chrono::milliseconds postponeUpdateUntilMS(
|
||||||
|
postponeUpdateUntil.time_since_epoch());
|
||||||
|
|
||||||
|
gPrefs->Write(
|
||||||
|
prefsUpdateScheduledTime,
|
||||||
|
wxString(std::to_string(postponeUpdateUntilMS.count())));
|
||||||
|
|
||||||
gPrefs->Flush();
|
gPrefs->Flush();
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
|
@ -18,10 +18,6 @@
|
|||||||
#include <wx/event.h>
|
#include <wx/event.h>
|
||||||
#include <wx/timer.h>
|
#include <wx/timer.h>
|
||||||
|
|
||||||
namespace UpdatesCheckingSettings {
|
|
||||||
extern AUDACITY_DLL_API BoolSetting DefaultUpdatesCheckingFlag;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// A class that managing of updates.
|
/// A class that managing of updates.
|
||||||
/**
|
/**
|
||||||
Opt-in request and show update dialog by the scheduled time.
|
Opt-in request and show update dialog by the scheduled time.
|
||||||
@ -31,13 +27,12 @@ namespace UpdatesCheckingSettings {
|
|||||||
class UpdateManager final : public wxEvtHandler
|
class UpdateManager final : public wxEvtHandler
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
UpdateManager();
|
UpdateManager() = default;
|
||||||
~UpdateManager();
|
|
||||||
|
|
||||||
static UpdateManager& GetInstance();
|
static UpdateManager& GetInstance();
|
||||||
static void Start();
|
static void Start();
|
||||||
|
|
||||||
void GetUpdates();
|
void GetUpdates(bool ignoreNetworkErrors);
|
||||||
|
|
||||||
VersionPatch GetVersionPatch() const;
|
VersionPatch GetVersionPatch() const;
|
||||||
|
|
||||||
@ -46,7 +41,6 @@ private:
|
|||||||
VersionPatch mVersionPatch;
|
VersionPatch mVersionPatch;
|
||||||
|
|
||||||
wxTimer mTimer;
|
wxTimer mTimer;
|
||||||
const int mUpdateCheckingInterval;
|
|
||||||
|
|
||||||
void OnTimer(wxTimerEvent& event);
|
void OnTimer(wxTimerEvent& event);
|
||||||
|
|
||||||
|
@ -45,7 +45,7 @@ UpdatePopupDialog::UpdatePopupDialog (wxWindow* parent, const VersionPatch& vers
|
|||||||
|
|
||||||
S.Id (DontShowID).AddCheckBox (
|
S.Id (DontShowID).AddCheckBox (
|
||||||
XO ("Don't show this again at start up"),
|
XO ("Don't show this again at start up"),
|
||||||
!UpdatesCheckingSettings::DefaultUpdatesCheckingFlag.Read());
|
!DefaultUpdatesCheckingFlag.Read());
|
||||||
|
|
||||||
S.Prop(1).AddSpace(1, 0, 1);
|
S.Prop(1).AddSpace(1, 0, 1);
|
||||||
|
|
||||||
@ -80,7 +80,7 @@ void UpdatePopupDialog::OnSkip (wxCommandEvent&)
|
|||||||
|
|
||||||
void UpdatePopupDialog::OnDontShow (wxCommandEvent& event)
|
void UpdatePopupDialog::OnDontShow (wxCommandEvent& event)
|
||||||
{
|
{
|
||||||
UpdatesCheckingSettings::DefaultUpdatesCheckingFlag.Write(!event.IsChecked());
|
DefaultUpdatesCheckingFlag.Write(!event.IsChecked());
|
||||||
}
|
}
|
||||||
|
|
||||||
HtmlWindow* UpdatePopupDialog::AddHtmlContent (wxWindow* parent)
|
HtmlWindow* UpdatePopupDialog::AddHtmlContent (wxWindow* parent)
|
||||||
|
@ -15,7 +15,7 @@ if( BUILDING_64_BIT )
|
|||||||
set( INSTALLER_X64_MODE "ArchitecturesInstallIn64BitMode=x64" )
|
set( INSTALLER_X64_MODE "ArchitecturesInstallIn64BitMode=x64" )
|
||||||
else()
|
else()
|
||||||
set( INSTALLER_SUFFIX "x86" )
|
set( INSTALLER_SUFFIX "x86" )
|
||||||
set( INSTALLER_X64_MODE "ArchitecturesInstallIn64BitMode=x64")
|
set( INSTALLER_X64_MODE "" )
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
if( SIGN )
|
if( SIGN )
|
||||||
|
@ -96,7 +96,7 @@ Source: ".\FirstTimeModel.ini"; DestDir: "{app}"; DestName: "FirstTime.ini"; Per
|
|||||||
Source: "Additional\README.txt"; DestDir: "{app}"; Flags: ignoreversion
|
Source: "Additional\README.txt"; DestDir: "{app}"; Flags: ignoreversion
|
||||||
|
|
||||||
Source: "Additional\LICENSE.txt"; DestDir: "{app}"; Flags: ignoreversion
|
Source: "Additional\LICENSE.txt"; DestDir: "{app}"; Flags: ignoreversion
|
||||||
Source: "{#AppExe}"; DestDir: "{app}"; Flags: ignoreversion
|
Source: "Package\*.exe"; DestDir: "{app}"; Flags: ignoreversion
|
||||||
|
|
||||||
; Manual, which should be got from the manual wiki using ..\scripts\mw2html_audacity\wiki2htm.bat
|
; Manual, which should be got from the manual wiki using ..\scripts\mw2html_audacity\wiki2htm.bat
|
||||||
@MANUAL@
|
@MANUAL@
|
||||||
|
Loading…
x
Reference in New Issue
Block a user