Jamoma API  0.6.0.a19
Appendix: C++ Coding Style Guide
Author
Jamoma, Timothy Place, Nathan Wolek, Trond Lossius

Variables

  • Declare all variables on separate lines.
  • If a variable is assigned immediately, then give it a default value in the declaration.
  • Prefer explicit types, e.g. TTObjectPtr rather than TTObject*.
  • User tabular formatting, as mentioned in the section "Whitespace"

Functions

Functions always appear:

  1. With the return type on the same line as the function name
  2. With the arguments on the same line as the function name, unless they dont fit. In this case they follow in tabular format below the first argument name.
  3. The open curly brace is on the line below the function name – not the same line.
  4. The closing curly brace is always on its own line
{
return this->directory;
}
  • Whitespace between two functions should generally be two blank lines.
  • There should never be two consecutive blank lines within a function.

Arguments

Prefer passing arguments as TTValueRef or const TTValueRef.

Whitespace

Multiple lines of similar function calls, similar definitions, should prefer tabular style formatting (which is to say, things are lined up in columns). This makes it faster to see the variant information between the lines, and also to edit multiple lines simultaneously using an editor such as TextMate.

Naming Conventions

Macros should be all upper case, words divided by underscores

Variables

  1. CamelCase.
  2. Variable names begin with lower-case letters
  3. Class Member variables begin with 'm'
  4. Constants begin with a 'k'
  5. Globals begin with 'g'
  6. Statics begin with 's'
  7. member method names begin with lower-case letters
  8. Classes or Global scope functions beggin with upper-case letters.
  9. Library functions begin with 'TT', non-library functions do not.

Casting

  1. Be wary of casting if the problem/warning can be avoided in another way.
  2. Readability is the most important thing. So we dont always use the crazy C++ casting stuff...
  3. Prefer C++ Style int(someValue) casts to (int)someValue casts.

Constructors

  1. for TTObject subclasses, use the appropriate macro (such as TT_OBJECT_CONSTRUCTOR) to implement the function signature correctly
  2. prefer initializers to assigning values
  3. initializers should be indented one tab

Doxygen documentation

Documentation of Jamoma's C++ source code is generated using specific annotations that can be extracted by Doxygen. In addition to the general features of Doxygen, we have developed several style conventions for Jamoma to provide consistency and ensure readability.

Header and source code files

At the top of header files seven key tags are necessary for consistent Doxygen documentation across Jamoma. The header files for TTSampleMatrix.h and TTBuffer.h can serves as examples for how to do this.

  • @file - identifies the file as a module that Doxygen should process
  • @ingroup - contains a tag representing the library or extension
  • @brief - single sentence that describes what the module does, ideally starting with a verb
  • @details - longer description that may be several sentences
  • @seealso - a list of related modules that you wish to link to
  • @authors - persons who have made significant conrtibutions to the module
  • @copyright - a failure consistent BSD licences description

This information is also to be copied across to the .cpp source file.

Classes

In the header file documentation of classes is typically expected to contain the following information.

  • @brief - single sentence that describes what the module does, ideally starting with a verb
  • @details - longer description that may be several sentences (where relevant)
  • @seealso - a list of related modules that you wish to link to (where relevant)

Because header files in the Jamoma Core typically document a single class, it is possible to make use of Doxygen's special commands for copying comments, thereby keeping our comments DRYer. These commands allow us to maintain a single set of brief and detailed comments at the top of our header files, but then apply those comments to both the header file and class definition. The following example from TTValue.h demonstrates these tags in use:

/** @copybrief TTValue.h
@copydetails TTValue.h
*/
class TTValue : public TTElementVector {

Variables

Each variables is provided with a brief description of its purpose, as in this example:

TTUInt16 mBitShift; ///< Amount of bits to shift away based on attrBitdepth.
TTSampleVector mAccumulator; ///< Holds values over from one vector to the next for each channel.
TTSampleVector mOutput; ///< Holds values over from one vector to the next for each channel..
TTUInt8 mBitdepth; ///< Use a range of 1 to 24 to emulate the specified bitdepth.
TTFloat64 mSrRatio; ///< Use a range of 0.0 to 1.0 to specify a ratio of the current sample-rate to emulate in order to intentional aliasing artifacts.

Methods

  • @brief - single sentence that describes what the method does, ideally starting with a verb
  • @details - longer description that may be several sentences
  • @param - each argument to the method is documented
  • @return - Documents the value returned by the method
  • @seealso - a list of related modules that you wish to link to

Example:

/** Assigns a vector of sample values to a channel in this signal.
@details The vector member of this class simply holds a pointer, not a copy of the data. This makes the
operation of this method (and others) fast, but also means that care should be taken to ensure
that the data being pointed to by this signal is valid, and does not become invalid during the
lifetime of the signal.
It is the responsibility of the user of this method to ensure that the sample-rate and vector-size
are also set correctly.
@param channel The channel number (zero-based) to assign the vector to.
@param vectorSize The number of samples in the vector.
@param newVector A pointer to the first sample in a vector of samples.
@result An error code.
*/
TTErr setVector(const TTChannelCount channel, const TTUInt16 vectorSize, const TTSampleValuePtr newVector);

If a given method is overloaded, it is possible to make use of Doxygen's overload command. Whenever this command is used, a full set of Doxygen comments should be placed on the first version of the method, followed by the overload tag for each subsequent version. Similar to the copy commands, this results in comments that are DRYer.

Common declarations

Jamoma's documentation attempts to gather common declaration types together using Doxygen's grouping features. To add these items to established groups, annotations should make use of the ingroup tag in addition to providing a suitable description. The following subsections provide examples of the ingroup tag in use.

Constants

Constants need to be indicated as being part of the const group.

/** \ingroup consts
Pre-calculated value of pi (3.1416).
*/
TTFOUNDATION_EXPORT extern const TTFloat64 kTTPi;
/** \ingroup consts
Pre-calculated value of pi/2.
*/
TTFOUNDATION_EXPORT extern const TTFloat64 kTTHalfPi;

Enumerations

Enumerations need to be indicated as being part of the enums group. The list of enumerations, as well as each of its values, are described:

/** \ingroup enums
Enumeration recording the audio processing state of each node of the graph.
*/
kTTAudioGraphProcessUnknown = 0, ///< The current processing status of the node is unknown.
kTTAudioGraphProcessNotStarted, ///< Audio processing has not yet started for this node.
kTTAudioGraphProcessingCurrently, ///< This node is currently processing audio.
kTTAudioGraphProcessComplete ///< This node has completed processing audio for now.
};

Bit masks

Bitmasks need to be indicated as being part of the bitmasks group. The list of bitmasks, as well as each of its values, are described:

/** \ingroup bitmasks
Enumeration flags signaling specific properties of this node.
Values are used as a bitmask.
*/
kTTAudioGraphFlagsNone = 0x00,
kTTAudioGraphProcessor = 0x01, ///< This node is an audio effect processor. It expects audio input that will be processed.
kTTAudioGraphGenerator = 0x02, ///< This object is an audio generator, and do not expect audio input.
kTTAudioGraphNonAdapting = 0x04, ///< This object does not adapt its number of output channels to the number of input channels
};

Typedefs

Typedefs need to be indicated as being part of the typedefs group:

/** Pointer to a #TTDictionary.
@ingroup typedefs
*/

Macros

Macros need to be indicated as being part of the macros group:

/** Internal macro used to locate the byte within mData where a specific component begins.
This macro is used by both get and set routines to ensure that the formula for access is consistent. Allows our interface to be consistent in its lookup method and represents a specific application of the <a href="http://en.wikipedia.org/wiki/Don't_repeat_yourself">DRY principle</a>.
@param i row in matrix
@param j column in matrix
@ingroup macros
*/
#define INDEX_OF_COMPONENT_FIRSTBYTE(i, j) \
{ \
(i * mColumnCount + j) * mComponentStride \
}