-
Notifications
You must be signed in to change notification settings - Fork 307
ImplementationStyleGuidelines
This page specifies coding guidelines for PortAudio contributors. Some guidelines pertain to mechanical style, others to quality of implementation issues. Since the PortAudio code is edited on many different platforms, using many different editors, these guideline should be followed to improve readability and consistency.
The PortAudio design guidelines are restated below. They apply to implementation as well as to API design:
- Implementation should be possible on all common computer music platforms.
- Clients of PortAudio should be able to achieve efficient, and ideally optimal use of the audio services on all target platforms.
- The API should be simple enough to be used by music students with minimal experience in C programming.
- The API should seek to provide only low-level audio services, and to only support those services directly available on the host platform.
Note that the last guideline has been relaxed with regard to audio sample formats and user buffer sizes - PortAudio can convert between a number of sample formats and can adapt to the user's buffer size requirements.
The following formatting conventions should be adhered to in all PortAudio code:
- TABs should NOT be used in .c and .h files; instead 4 spaces should be used. Makefiles should continue to use TABs since this is required by Make.
- Line-end characters will be consistent with the platform on which the source has been checked out of SVN (SVN handles this).
- Brace placement will follow ANSI style. For example:
if( aCondition )
{
DoSomething();
}
else
{
DoSomethingElse();
}
- Functions and typedefs will start with zero indentation.
- Function prototypes will fit on one line if they are not too long.
- Lines should not exceed 120 characters in length.
- Long lines may be continued across multiple lines.
- Continuation lines should either be indented by 8 spaces, or aligned with the first parameter. For example:
PaError PaXyz_ThumpStream( PaStream *stream );
PaError PaXyz_FillBuffer( PaStream *stream,
float *buffer,
int numThings );
PaError PaXyz_DoSomethingWithLongName(
PaStream *stream,
int quality,
int numThings );
- C-Style comments should be used:
/* this comment is OK */
// this comment is NOT OK
- Multi-line comments should match this format:
/* In multi-line comments, the first line of text
* should be on the same line as the opening *
* The left margin should be vertically aligned with
* one space between the * and the text.
*/
If the style is not specified here, when in doubt, follow the conventions of the surrounding code.
"AStyle":http://astyle.sourceforge.net <"http://astyle.sourceforge.net":http://astyle.sourceforge.net> has been proposed as helpful tool for cleaning code, however we don't intend to use it on an ongoing basis. It is expected that contributors of each implementation will take responsibility for keeping their code clean.
The following coding guidelines should be followed in order to establish a quality baseline for our implementations:
- All code should be written in C++-compatible plain ANSI C89. We suggest that all implementations should compile silently with both "
gcc -ansi -pedantic -Wall
" and "g++ -ansi -pedantic -Wall
". An exception is host-api modules that must be written in C++ (e.g. pa_asio.cpp). In this case a maximally compatible dialect of C++98 should be used. - Always code defensively. Where necessary, think of PortAudio as a heavyweight library rather than a lightweight wrapper. Efficiency is important where it matters (e.g. in real-time callbacks) but safety is important everywhere.
- All parameters passed to PortAudio by the user should be validated, and error codes returned where necessary. All reasonable efforts should be made to minimize the risk of a crash resulting from passing incorrect parameters to PortAudio.
- Error handling should be complete. Every host function that can return an error condition should have its status checked. PortAudio may attempt to recover from errors in some cases, but generally error codes should be returned to the client.
- In almost all cases, a PortAudio error code should be preferred to returning
paHostError
. If a new PortAudio error code is needed it should be discussed on the mailing list to coordinate updating portaudio.h - PortAudio code should not leak resources. After
Pa_Terminate()
is called, implementations should ensure that all dynamically allocated resources have been freed. - The definition of the PortAudio API should minimize "implementation defined behavior". For example, calling functions such as
Pa_Initialize()
after PortAudio is initialized, orPa_Terminate()
after PortAudio has been terminated has well defined behavior. - Minimize dependence on ANSI C runtime on platforms where it would have to be loaded separately (e.g. on Win32 prefer Win32 API functions such as
GlobalAlloc()
to ANSI C functions such asmalloc()
).
It has been suggested that we make an effort to minimize the use of global and static data in PortAudio implementations. Another related goal is to reduce name pollution in the global scope. Some provisional guidelines are:
- Implementations should avoid exporting any symbols except where absolutely necessary. Specifically, global data must be declared statically. The next section documents naming conventions for all PortAudio symbols.
- Implementations should minimize their use of static data.
When in doubt, discuss it on the mailing list.
The assert()
macro should be avoided. In particular assert()
must not be used to handle failures in external APIs.
Assertions should only be used to verify invariants of code that is under full PortAudio control. e,g, both a caller and callee are PortAudio code, and the callee is responsible for maintaining the invariant. Even then, we'd prefer retuning paInternalError whenever possible.
Assertions should not be used to check return values of code that is not under PortAudio control (external code), such as operating system functions or native host audio API functions. Unexpected problems caused by external code can be handled by returning paUnanticipatedHostError.
- All
#defines
begin withPA_
- All
#defines
local to a file end with_
- All global utility variables begin with
paUtil
- All global utility types begin with
PaUtil
(including function types) - All global utility functions begin with
PaUtil_
- All static variables end with
_
- All static constants begin with
const
and end with_
(e.g.:constMyMagicNumber_
) - All static functions have no special prefix/suffix
- Platform-specific shared functions should begin with
Pa<PN>
_ wherePN
is the platform name. eg.PaWin_
for Windows,PaUnix_
for Unix.
In general, implementations should declare all of their members static, except for their initializer, which should be exported. All exported names should be preceded by Pa<MN>_
where <MN>
is the module name, for example the Windows MME initializer should be named PaWinMme_Initialize()
.
If it is necessary for implementations to define non-static symbols, they should use the following naming conventions, where is the module name such as WinMme.
- global variables should begin with
pa<MN>
- global types should begin with
Pa<MN>
- global utility functions should begin with
Pa<MN>_
Two utilities for debug messages are provided:
- The PA_DEBUG macro defined in
pa_debugprint.h
provides a simple way to print debug messages to stderr. In order to enable this feature, PortAudio should be built withPA_ENABLE_DEBUG_OUTPUT
defined (passing the--enable-debug-output
flag to the configure script or setting it in the "Preprocessor definitions"). Due to real-time performance issues,PA_DEBUG
may not be suitable for use within the PortAudio processing callback, or in other threads. - When real-time event tracing is required it is best to use the facility provided in
pa_trace.h
. In order to enabled this feature,PA_TRACE_REALTIME_EVENTS
should be set to 1 in the filepa_trace.h
when building PortAudio. IfPA_LOG_API_CALLS
is defined, all calls to the public PortAudio API will be logged to stderr along with parameters and return values.
At a minimum, each source and header file should contain a doxygen file
doc comment with a brief
description and an in_group
specification. For example:
/** @file
@ingroup common_src
@brief Buffer Processor implementation.
*/
Note that these requirements can be checked by running the doc/utils/checkfiledocs.py
script as follows:
$ cd doc/utils
$ python checkfiledocs.py
It will print a list of all violations.
Functions and structures intended for use by other modules should contain doxygen doc strings for each function and its parameters, and for each structure and its members. For an example, see src/common/pa_ringbuffer.h
.