Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
Loading...
This documentation is geared toward directing developers to any relevant information that they may need to access efficiently/quickly without having to spend too much time searching through nested links.
New to open source? Check out Introduction to Audacity development
The go-to place for information for contributors is the Contributing Documentation. Some other sources for important information that may be necessary or useful as a developer are listed below:
Building Instructions - How to download and build the code.
Code of Conduct - The standards to keep in mind when contributing.
License File - The open-source license that Audacity uses.
Coding Standards - Conventions and syntax/methods to consider when coding.
Other Contributions to Audacity - Section that is focused on ways to contribute to Audacity other than just working with source code.
This section is geared toward general information on how to use the software in its current state.
Audacity Manual - The provided manual on how to use Audacity and its features.
Audacity Support - Tutorials, changelogs and more
This section focuses on information regarding contributions to Audacity other than source code work like bug fixes, completing issues, and adding/working on new features. One pertinent part of non-coding contributions for Audacity focuses on creating task-based tutorials. So, a tutorial that shows users how to perform specific tasks with Audacity. Also, see the links below for similar information:
Contributing to Audacity - Page from Audacity's support community that provides links and information for the different ways to contribute to Audacity (other than just coding contributions).
Tutorial Style Guide - Page regarding the style and standards expected for tutorial contributions.
Note: Audacity is currently undergoing major restructuring. It currently is not an easy project to contribute code to, especially if you're new to programming.
For those who are looking to make their first contribution to Audacity see the Good First Issues label under the issues tab. Similarly, see the contribute page with issues specifically geared to new contributors.
Build instructions can be found in BUILDING.md.
Audacity is generally not well-suited to newcomers to the open source world. There's many reasons for it:
Audacity is over 20 years old, and the code base is thus generally convoluted and difficult to get into.
Audacity is highly complex as there simply are many things it does.
The Audacity team is very small, and there isn't much dev manpower to go around to mentor newcomers.
Audacity is written in C++, which means there's classes of errors (especially regarding memory safety) which you may not be familiar with if you're coming from other languages.
For these reasons and many more, it's generally not advisable to come fresh into open source development and start with Audacity. At least, not directly.
While contributing code to Audacity directly is hard, there are several things you can do instead:
Audacity supports many plugin formats (VST2, VST3, LV2, LADSPA, Audio Units, Nyquist, and VAMP).
If you develop a plugin, you'll have to worry about way fewer things than if you were to do the same thing in Audacity directly, while achieving the same result. Head over to the following places to learn more:
JUCE, a framework for audio effect plugins, using C++: https://juce.com/learn/tutorials/
Nyquist, Audacity's homebrew plugin format, using a Lisp dialect: Creating your own Nyquist Plugins
VAMP, a framework for audio analysis plugins, using C++ or Python: https://www.vamp-plugins.org/develop.html
While getting code into Audacity is hard, other efforts are both easier and more impactful to the community. Head over to https://support.audacityteam.org/community/contributing to learn more.
In very vague terms, the playbook for code contribution probably can look like thus:
Run into an issue which annoys you. Preferably something small which feels like it should be an easy fix.
Search the issue tracker if the bug already is reported. If not, write a report yourself.
Attempt to fix the bug.
Test whether the fix actually solves the bug, and if it has unintended side effects. BUILDING.md is helpful here to get you a testable build.
Submit a PR on Github with your fix, following the template checklist for the PR.
Wait for a bit. There typically should be someone taking a look at your PR within a week or so. If not, you can ask on the dev discord - audacityteam.org/devserver.
If changes get requested on your PR, try to implement them. If you don't know how to implement them, asking for help is fine (though, as outlined above - mentoring capacities are very limited), but abandoning the PR is equally fine. If the PR gets approved, it will undergo QA and finally, get merged.
If you are looking to fix a previously reported bug, there's no need to ask for permission in the bug tracker. Just give it a go and attempt to fix it!
While we're not particularly insistent about coding standards, there are a few things that we try to do consistently as below.
When modifying existing files, the main things are:
spaces, no tabs
three spaces per indent
As far as naming:
classes and methods/functions are in CamelCase
local variables are firstLoweredCamelCase
member variables are mVar
globals are usually gVar
Our style (and that of wxWidgets) is to not leave a space between a function name like 'GetAllFormats' and the following '(', so please copy that style too. It can make searching for functions easier.
If you're defining a complex macro, add a comment. You may understand it without a comment. We might not.
When you're using a #ifdef to give different bodies to a function, and the function is fairly long, we prefer that the #ifdef include the function header, the '{' and the closing '}' inside it rather than 'sharing' them between the two versions. We think the slight duplication is worth it for the better readability.
Source files are in UTF-8 format (so they may contain accented and other characters where necessary). This ensures they are processed the same by all compilers on all platforms
Do's:
Ensure declaration and definition use the same type (not typedefed names that happen to be the same).
Ensure when using functions like wxPrintf, wxString::Format, wxString::Printf and passing a wxString, the wxString::c_str() method is used to pass the correct value. Otherwise, a compilation error will occur with the GCC compiler (Mac and Linux systems).
Place user interface strings inside _() (not wxT() which is used for non-translated or testing-only strings). This ensures gettext can extract the strings for translation. Any strings that are context-dependent or need explanation should be prefaced with a comment starting "i18n-hint:".
Don't's:
Prefix member functions with the class name in the header - it's a GCC compiler error.
If you're adding new files into Audacity source there is boilerplate header we like to use:
Some files will have wxWidgets license rather than GPL. The second part of the header, starting with the line ending in //**
is a Doxygen class-level comment on the class defined within the source file.
We're also slowly moving towards more Doxygen friendly code, so comments at the start of functions with the Doxygen /// marker are encouraged. We're not planning on having everything Doxygenated. We do aim to have doxygen comments at the class level for all classes.
See Making Audacity Doxygenable for details.
Note that some header files (.h) don't contain class declarations for classes defined in the corresponding C++ files (.cpp). These are described at Unusual Header Files; note in particular the Guidelines for using Experimental.h.
Do not use "naked" new and delete!
A comprehensive rewriting of naked new and delete in Audacity's source (not including the third party lib-src directories) was completed early in 2.2.0 development. Do not reintroduce such code. Learn the use of smart pointers and containers instead.
That is, do not manage allocated memory thus:
but rather thus:
The use of delete is now implied in the destructor of pObj, whose type is std::unique_ptr< Obj, std::default_delete< Obj > >.
The advantage is not merely elimination of one line of code.
It is now unnecessary for a reviewer to examine all the other lines, to be sure that there is no other early return path from the function, on which the programmer neglected to duplicate the delete statement.
The deletion is guaranteed in case the function exits because an exception is thrown, by a statement which might even be outside the body of the function itself.
To achieve completely equivalent safety with naked new and delete would require the verbosity of try, catch, duplicated delete, and re-throw.
The principle generalizes to the management of other resources than memory.
Do not rely on explicit calls that free resources (such as open files). Rather, have that happen in the destructor of some "smart" variable.
You may free a resource explicitly where there is a need to do that, conditionally, earlier than the end of scope, or to check error codes. Still, use a smart variable to guarantee the ultimate freeing along all possible paths, including throws.
If you must free early and unconditionally, consider limiting the scope of the smart variable with braces { } so that the freeing code is still implicit.
Do not make calls that acquire the resource without immediately entrusting the responsibility to free it to such a variable.
One somewhat frequent example of a non-memory resource is the locking and unlocking of a mutex. wxMutex lets you call its Lock() and Unlock() methods explicitly, but it is better instead to initialize a variable of type wxMutexLocker.
This idiom is often called RAII in the literature on C++, which stands for "Resource Acquisition Is Initialization."
Some complex, mutative operation, involving multiple steps that might fail, is done on one or more objects. What are the possible outcomes? Know these terms, which are used in comments.
This is not as strong as the no-fail guarantee, which refers generally and abstractly to "failure." Rather, this refers only to the language-technical matter of throwing of exceptions, which is only one way that failure might be signalled -- another way is the returning of error codes.
Almost always, destructors of C++ classes should give a no-throw guarantee, because if a destructor is executed during stack unwinding of one exception, whose catch block is not yet reached, but then a second exception escapes the destructor -- then this is a catastrophe that aborts the program at once.
The operation promises not to fail! This is the strongest guarantee.
Swapping operations of containers or smart pointers often give this guarantee. Such a guarantee is often used to implement the (weaker) "strong guarantee" (below).
Failure may happen, but if it does, then it is guaranteed that the objects remain unchanged.
Often an object implements a mutating operation with strong guarantee, by building up alternative state in stack variables, making no change in the object's own state. Only after that build-up succeeds, the changes are committed: the new contents are swapped into the object's member variables, and the old contents, now held by stack variables, are destroyed.
This is like committing and rolling-back of transactions in databases, and indeed similar terminology is sometimes used in code and comments.
This relies on (stronger) no-fail guarantees in the commitment steps. (For otherwise, suppose one swap succeeds, but the second fails. What then, to regain a consistent state? Undo the first swap, which might then fail? Uh oh.)
A complicated operation may fail in the middle, leaving some side effects. It is guaranteed that the objects remain in some unspecified but "consistent" state.
What does "consistent" mean? That may vary, and there may be degrees of weak guarantee. But at a minimum it means this: the objects can be destroyed without crashes or other undefined behavior.
A complicated object might be composed of other objects that provide strong guarantees on their operations. A higher-level operation implemented in terms of the strong-guarantee operations may achieve only weak guarantees.
Operations on an Audacity project might fail for reasons such as i/o errors or the user cancelling a progress dialog. There is no attempt to recover from exhaustion of memory. For recoverable failures:
Editing operations that, when successful, can be undone and redone, supply a strong guarantee that the state of the project before the attempted operation is restored.
An exception to that is recording, which guarantees that the project will save some initial portion of the sound, captured before the error was detected.
Saving operations guarantee that a formerly saved project is not overwritten and no new project is created.
Export operations guarantee that previously existing files are not overwritten and no new but unusable files are created.
What follows describes the strategy to achieve these guarantees.
Many errors are signalled by raising exceptions. It is easier not to test and propagate error values through many levels of stack. These levels, though not checking errors, still must be written with some care, including but not limited to the use of RAII as described above. (One might say each function must implement a strong guarantee for its net resource allocation. Likewise for other side-effects that outlast its invocation, but with some exemptions described below.) Such techniques are sufficient to supply the guarantees for saving and exporting.
For editing operations on the internal state of the Audacity project, it is more complicated.
Exceptions are caught in numerous places by the template function GuardedCall, which wraps a lambda expression in a try-catch block. These include places where a no-throw guarantee is required, such as in callback functions that are passed to third-party libraries, or where exceptions are caught in a worker thread, as during recording.
Not all exceptions will be caught by GuardedCall. Audacity relies on a catch block of last resort in the event loops implemented in wxWidgets. The function AudacityApplication::OnExceptionInMainLoop is called back from inside the catch block and handles the exception.
If the caught exception is of a class derived from AudacityException, then all of these handlers use wxEventHandler::CallAfter to enqueue delayed actions, to be done always in the main thread at the next idle time of the event loop. It is here that the previous state of the project is restored, rolling back to the last committed state of the Undo history; or in case of recording, that asynchronous recording action is stopped and partial results are committed to the history. Then the user is notified of some details of the cause of failure in a way determined by the exception object. (If the caught exception is of some other class, recovery is not implemented, and in most cases the program will crash.)
Therefore, the many functions that implement editing operations by changing the undoable state of the project are relieved of the responsibility to provide strong guarantees. Generally, all that is needed is the very weak guarantee that modified Tracks and other objects remain destructible.
This is most pertinent to the classes WaveTrack, WaveClip, and Sequence that frequently write BlockFile objects and are exposed to the risk of i/o errors. It is commented in each of their mutative operations how strong a guarantee is provided.
Sequence provides a strong guarantee for everything, even if that exceeds requirements. It is uncomplicated to do this, as Sequence is essentially an array of samples with a persistent back-up, for which the build and swap pattern is sufficient.
WaveClip, which may recursively contain other WaveClips, each with its own Sequence, and WaveTrack, which may contain multiple WaveClips, do not always implement strong guarantees. It is documented in comments where more than a basic weak guarantee was achievable, though usually only this basic guarantee is really needed. The exceptions to this are the appending operations, where some stronger promise is needed to support partial success in recording. Previous contents will be preserved, and some initial (possibly empty) portion of the data intended for appending will be appended.
Format strings are often used in Audacity to insert variables into pre-defined strings. So for example:
_()
is for translatable strings (see below)
%d
and %f are placeholders which get replaced by the parameters (here: underruns
, last_underrun
)
If you need to switch up the order of the placeholder relative to the order the parameters are listed in, insert a %1$
between the %
and letter of the placeholder:
Audacity uses gettext for translations. Because of this, the following rules apply:
Translatable strings look like this: _("Translate me")
Untranslatable strings look like this: wxT("do not translate")
Strings which should be extracted for translation, but not translated at runtime look like this: XO("extract only")
Empty strings must be untranslatable: wxT("")
Mark all strings as either translatable or untranslatable, even if it's just _("%s: %s")
- some languages have different punctuation conventions.
All whitespace within strings gets rendered, both in Audacity and translation software.
Long strings may stay as long strings, or be broken up with \
. So for example:
Different languages prefer different word orders, so keep strings in one piece using format substitutions. For example:
Some parts of the code use HTML.
Don't mark HTML tags as translatable.
Avoid using HTML inside of translatable strings.
Some parts use Wiki syntax for links (ie [[page name|link title]]
).
Only the link title gets translated.
Menu items may have access keys, denoted with an & in the string. For example: _("&Loop Play")
renders as Loop Play in the menu when the user is navigating with access keys.
It's up to translators which letter becomes the access key, as long as it doesn't conflict with other access keys in the same menu.
The Effects menu, the Generate menu and the Analyze menu do not use access keys.
wxString::Format
is wxWidget's implementation of a return.
Use the wxPLURAL macro for for (ie singular/plural - some languages do it differently):
Audacity supports the following formats:
Nyquist (Lisp or SAL) Audacity's built-in scripting format. Allows for easy generation of UI elements and already is tuned to Audacity's needs. Note that this plugin format is not supported as realtime effects. Documentation: Creating your own Nyquist Plugins
VST3 (C++) The industry standard for plugins. Widely supported across Audacity, Musescore and most DAWs. Documentation: https://steinbergmedia.github.io/vst3_doc/vstsdk/index.html
LV2 (C, C++, other C-compatible languages) The Linux plugin standard. Widely supported across open source software. Documentation: https://lv2plug.in/book/
Vamp (C++, Python) An easy-to-develop-for framework for audio analyzers. Documentation: https://www.vamp-plugins.org/develop.html
Additionally, LADSPA, VST2.4 and Audio Units are supported. LADSPA and VST2.4 are the predecessor to LV2 and VST3, respectively, and thus fairly outdated. Audio Units are only available on macOS.
Further, Audacity has modules, which allow extending Audacity beyond just editing audio. It is somewhat experimental and not yet documented.
Audacity supports the following scripting formats:
mod-script-pipe (Python, Perl) A module that exposes a named pipe to which commands can be sent. Documentation: https://manual.audacityteam.org/man/scripting.html
Macros You can use Audacity's macros feature to chain effects and actions together. This can be exported as a file. Documentation: https://manual.audacityteam.org/man/macros.html
If you have found a macro or script which you find universally applicable, you can share it in the scripts section.