Skip to content

Commit

Permalink
Merge tag '1.1.2' into develop
Browse files Browse the repository at this point in the history
  • Loading branch information
adamstark committed Nov 18, 2024
2 parents 98b3c89 + 3d899f5 commit 1713396
Show file tree
Hide file tree
Showing 2 changed files with 150 additions and 151 deletions.
2 changes: 1 addition & 1 deletion CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
#===============================================================================
cmake_minimum_required (VERSION 3.12)

project ("AudioFile" VERSION 1.1.1
project ("AudioFile" VERSION 1.1.2
DESCRIPTION "A simple C++ library for reading and writing audio files."
HOMEPAGE_URL "https://github.com/adamstark/AudioFile")

Expand Down
299 changes: 149 additions & 150 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,191 +1,189 @@
# AudioFile

<!-- Version and License Badges -->
![Version](https://img.shields.io/badge/version-1.1.1-green.svg?style=flat-square)
![License](https://img.shields.io/badge/license-MIT-blue.svg?style=flat-square)
![Language](https://img.shields.io/badge/language-C++-yellow.svg?style=flat-square)

A simple header-only C++ library for reading and writing audio files.
![Version](https://img.shields.io/badge/version-1.1.2-green.svg?style=flat-square)
![License](https://img.shields.io/badge/license-MIT-blue.svg?style=flat-square)
![Language](https://img.shields.io/badge/language-C++-yellow.svg?style=flat-square)

A simple header-only C++ library for reading and writing audio files.

Current supported formats:

* WAV
* AIFF
- WAV
- AIFF

Author
------
## Author

AudioFile is written and maintained by Adam Stark.

[http://www.adamstark.co.uk](http://www.adamstark.co.uk)

Usage
-----
## Usage

### Create an AudioFile object:

#include "AudioFile.h"
#include "AudioFile.h"

AudioFile<double> audioFile;

AudioFile<double> audioFile;
### Load an audio file:

audioFile.load ("/path/to/my/audiofile.wav");
audioFile.load ("/path/to/my/audiofile.wav");

### Get some information about the loaded audio:

int sampleRate = audioFile.getSampleRate();
int bitDepth = audioFile.getBitDepth();
int numSamples = audioFile.getNumSamplesPerChannel();
double lengthInSeconds = audioFile.getLengthInSeconds();
int numChannels = audioFile.getNumChannels();
bool isMono = audioFile.isMono();
bool isStereo = audioFile.isStereo();
// or, just use this quick shortcut to print a summary to the console
audioFile.printSummary();
int sampleRate = audioFile.getSampleRate();
int bitDepth = audioFile.getBitDepth();

int numSamples = audioFile.getNumSamplesPerChannel();
double lengthInSeconds = audioFile.getLengthInSeconds();

int numChannels = audioFile.getNumChannels();
bool isMono = audioFile.isMono();
bool isStereo = audioFile.isStereo();

// or, just use this quick shortcut to print a summary to the console
audioFile.printSummary();

### Access the samples directly:

int channel = 0;
int numSamples = audioFile.getNumSamplesPerChannel();
int channel = 0;
int numSamples = audioFile.getNumSamplesPerChannel();

for (int i = 0; i < numSamples; i++)
{
double currentSample = audioFile.samples[channel][i];
}
for (int i = 0; i < numSamples; i++)
{
double currentSample = audioFile.samples[channel][i];
}

### Replace the AudioFile audio buffer with another

// 1. Create an AudioBuffer
// (BTW, AudioBuffer is just a vector of vectors)
AudioFile<double>::AudioBuffer buffer;
// 2. Set to (e.g.) two channels
buffer.resize (2);
// 3. Set number of samples per channel
buffer[0].resize (100000);
buffer[1].resize (100000);
// 4. do something here to fill the buffer with samples, e.g.
#include <math.h> // somewhere earler (for M_PI and sinf())
// then...
int numChannels = 2;
int numSamplesPerChannel = 100000;
float sampleRate = 44100.f;
float frequency = 440.f;

for (int i = 0; i < numSamplesPerChannel; i++)
{
// 1. Create an AudioBuffer
// (BTW, AudioBuffer is just a vector of vectors)

AudioFile<double>::AudioBuffer buffer;

// 2. Set to (e.g.) two channels
buffer.resize (2);

// 3. Set number of samples per channel
buffer[0].resize (100000);
buffer[1].resize (100000);

// 4. do something here to fill the buffer with samples, e.g.

#include <math.h> // somewhere earler (for M_PI and sinf())

// then...

int numChannels = 2;
int numSamplesPerChannel = 100000;
float sampleRate = 44100.f;
float frequency = 440.f;

for (int i = 0; i < numSamplesPerChannel; i++)
{
float sample = sinf (2. * M_PI * ((float) i / sampleRate) * frequency) ;

for (int channel = 0; channel < numChannels; channel++)
buffer[channel][i] = sample * 0.5;
}

// 5. Put into the AudioFile object
bool ok = audioFile.setAudioBuffer (buffer);


### Resize the audio buffer

// Set both the number of channels and number of samples per channel
audioFile.setAudioBufferSize (numChannels, numSamples);

// Set the number of samples per channel
audioFile.setNumSamplesPerChannel (numSamples);

// Set the number of channels
audioFile.setNumChannels (numChannels);

}

// 5. Put into the AudioFile object
bool ok = audioFile.setAudioBuffer (buffer);

### Resize the audio buffer

// Set both the number of channels and number of samples per channel
audioFile.setAudioBufferSize (numChannels, numSamples);

// Set the number of samples per channel
audioFile.setNumSamplesPerChannel (numSamples);

// Set the number of channels
audioFile.setNumChannels (numChannels);

### Set bit depth and sample rate
audioFile.setBitDepth (24);
audioFile.setSampleRate (44100);

audioFile.setBitDepth (24);
audioFile.setSampleRate (44100);

### Save the audio file to disk

// Wave file (implicit)
audioFile.save ("path/to/desired/audioFile.wav");

// Wave file (explicit)
audioFile.save ("path/to/desired/audioFile.wav", AudioFileFormat::Wave);

// Aiff file
audioFile.save ("path/to/desired/audioFile.aif", AudioFileFormat::Aiff);

// Wave file (implicit)
audioFile.save ("path/to/desired/audioFile.wav");

// Wave file (explicit)
audioFile.save ("path/to/desired/audioFile.wav", AudioFileFormat::Wave);

Examples
-----------------
// Aiff file
audioFile.save ("path/to/desired/audioFile.aif", AudioFileFormat::Aiff);

Please see the `examples` folder for some examples on library usage.
## Examples

Please see the `examples` folder for some examples on library usage.

A Note On Types
-----------------
## A Note On Types

AudioFile is a template class and so it can be instantiated using different types to represent the audio samples.

For example, we can use floating point precision...

AudioFile<float> audioFile;
AudioFile<float> audioFile;

...or double precision...

AudioFile<double> audioFile;
AudioFile<double> audioFile;

...or an integer type:

AudioFile<int> audioFile;
This simply reflects the data type you would like to use to store the underlying audio samples.
AudioFile<int> audioFile;

This simply reflects the data type you would like to use to store the underlying audio samples.

When you use an integer type to store the samples (e.g. `int` or `int8_t` or `int16_t` or `uint32_t`), the library will read in the integer sample values directly from the audio file.
When you use an integer type to store the samples (e.g. `int` or `int8_t` or `int16_t` or `uint32_t`), the library will read in the integer sample values directly from the audio file.

A couple of notes on integer types:

* The range of samples is designed to be symmetric. This means that for (e.g.) an signed 8-bit integer (`int8_t`) we will use the range `[-127, 127]` for storing samples representing the `[-1., 1.]` range. The value `-128` is possible here given the `int8_t` type, but this is interpreted as a value slightly lower than `-1` (specifically `-1.007874015748`).
- The range of samples is designed to be symmetric. This means that for (e.g.) an signed 8-bit integer (`int8_t`) we will use the range `[-127, 127]` for storing samples representing the `[-1., 1.]` range. The value `-128` is possible here given the `int8_t` type, but this is interpreted as a value slightly lower than `-1` (specifically `-1.007874015748`).

* In the case of unsigned types, we obviously can't store samples as negative values. Therefore, we used the equivalent range of the unsigned type in use. E.g. if with a 8-bit signed integer (`int8_t`) the range would be `[-127, 127]`, for an 8-bit unsigned integer we would use the range `[1, 255]`. Note that we don't use `-128` for `int8_t` or `0` in `uint8_t`.
- In the case of unsigned types, we obviously can't store samples as negative values. Therefore, we used the equivalent range of the unsigned type in use. E.g. if with a 8-bit signed integer (`int8_t`) the range would be `[-127, 127]`, for an 8-bit unsigned integer we would use the range `[1, 255]`. Note that we don't use `-128` for `int8_t` or `0` in `uint8_t`.

* If you try to read an audio file with a larger bit-depth than the type you are using to store samples, the attempt to read the file will fail. Put more simply, you can't read a 16-bit audio sample into an 8-bit integer.
- If you try to read an audio file with a larger bit-depth than the type you are using to store samples, the attempt to read the file will fail. Put more simply, you can't read a 16-bit audio sample into an 8-bit integer.

* If you are writing audio samples in integer formats, you should use the correct sample range for both a) the type you are using to store samples; and b) the bit depth of the audio you want to write.
- If you are writing audio samples in integer formats, you should use the correct sample range for both a) the type you are using to store samples; and b) the bit depth of the audio you want to write.

The following table details the sample range for each bit-depth:

| Type | 8-bit Audio | 16-bit Audio | 24-bit Audio | 32-bit Audio |
| ------------- | ------------- | ------------- | ------------- | ------------- |
| `float` | `[-1.0, 1.0]` | `[-1.0, 1.0]` | `[-1.0, 1.0]` | `[-1.0, 1.0]` |
| `double` | `[-1.0, 1.0]` | `[-1.0, 1.0]` | `[-1.0, 1.0]` | `[-1.0, 1.0]` |
| `int8_t` | `[-127, 127]` | :x: (type too small) | :x: (type too small) | :x: (type too small) |
| `uint8_t` | `[1, 255]` | :x: (type too small) | :x: (type too small) | :x: (type too small) |
| `int16_t` | `[-127, 127]` | `[-32767, 32767]` | :x: (type too small) | :x: (type too small) |
| `uint16_t` | `[1, 255]` | `[1, 65535]` | :x: (type too small) | :x: (type too small) |
| `int32_t` | `[-127, 127]` | `[-32767, 32767]` | [`-8388607, 8388607]` | `[-2147483647, 2147483647]` |
| `uint32_t` | `[1, 255]` | `[1, 65535]` | `[1, 16777215]` | `[1, 4294967295]` |
| `int64_t` | `[-127, 127]` | `[-32767, 32767]` | [`-8388607, 8388607]` | `[-2147483647, 2147483647]` |
| `uint64_t` | `[1, 255]` | `[1, 65535]` | `[1, 16777215]` | `[1, 4294967295]` |
| Type | 8-bit Audio | 16-bit Audio | 24-bit Audio | 32-bit Audio |
| ---------- | ------------- | -------------------- | --------------------- | --------------------------- |
| `float` | `[-1.0, 1.0]` | `[-1.0, 1.0]` | `[-1.0, 1.0]` | `[-1.0, 1.0]` |
| `double` | `[-1.0, 1.0]` | `[-1.0, 1.0]` | `[-1.0, 1.0]` | `[-1.0, 1.0]` |
| `int8_t` | `[-127, 127]` | :x: (type too small) | :x: (type too small) | :x: (type too small) |
| `uint8_t` | `[1, 255]` | :x: (type too small) | :x: (type too small) | :x: (type too small) |
| `int16_t` | `[-127, 127]` | `[-32767, 32767]` | :x: (type too small) | :x: (type too small) |
| `uint16_t` | `[1, 255]` | `[1, 65535]` | :x: (type too small) | :x: (type too small) |
| `int32_t` | `[-127, 127]` | `[-32767, 32767]` | [`-8388607, 8388607]` | `[-2147483647, 2147483647]` |
| `uint32_t` | `[1, 255]` | `[1, 65535]` | `[1, 16777215]` | `[1, 4294967295]` |
| `int64_t` | `[-127, 127]` | `[-32767, 32767]` | [`-8388607, 8388607]` | `[-2147483647, 2147483647]` |
| `uint64_t` | `[1, 255]` | `[1, 65535]` | `[1, 16777215]` | `[1, 4294967295]` |

Error Messages
-----------------
## Error Messages

By default, the library logs error messages to the console to provide information on what has gone wrong (e.g. a file we tried to load didn't exist).
By default, the library logs error messages to the console to provide information on what has gone wrong (e.g. a file we tried to load didn't exist).

If you prefer not to see these messages, you can disable this error logging behaviour using:

audioFile.shouldLogErrorsToConsole (false);
audioFile.shouldLogErrorsToConsole (false);

## Versions

##### 1.1.2 - 18th November 2024

Versions
-------
- Improved AIFF sample rate calculations
- Improved CMake support
- Code improvements
- Bug and warning fixes

##### 1.1.1 - 4th April 2023

Expand Down Expand Up @@ -219,7 +217,7 @@ Versions
##### 1.0.6 - 29th February 2020

- Made error logging to the console optional
- Fixed lots of compiler warnings
- Fixed lots of compiler warnings

##### 1.0.5 - 14th October 2019

Expand All @@ -239,38 +237,39 @@ Versions

- Bug fixes

Contributions
-------
## Contributions

Many thanks to the following people for their contributions to this library:

* [Abhinav1997](https://github.com/Abhinav1997)
* [alxarsenault](https://github.com/alxarsenault)
* [BenjaminHinchliff](https://github.com/BenjaminHinchliff)
* [BesselJ](https://github.com/BesselJ)
* [emiro85](https://github.com/emiro85)
* [heartofrain](https://github.com/heartofrain)
* [helloimmatt](https://github.com/helloimmatt/)
* [leocstone](https://github.com/leocstone)
* [MatthieuHernandez](https://github.com/MatthieuHernandez)
* [mrpossoms](https://github.com/mrpossoms)
* [mynameisjohn](https://github.com/mynameisjohn)
* [Sidelobe](https://github.com/Sidelobe)
* [sschaetz](https://github.com/sschaetz)
* [Yhcrown](https://github.com/Yhcrown)

Want to Contribute?
-------
- [Abhinav1997](https://github.com/Abhinav1997)
- [alxarsenault](https://github.com/alxarsenault)
- [ascii255](https://github.com/ascii255)
- [BenjaminHinchliff](https://github.com/BenjaminHinchliff)
- [BesselJ](https://github.com/BesselJ)
- [cgraf78](https://github.com/cgraf78)
- [emiro85](https://github.com/emiro85)
- [encoded](https://github.com/encoded)
- [heartofrain](https://github.com/heartofrain)
- [helloimmatt](https://github.com/helloimmatt/)
- [leocstone](https://github.com/leocstone)
- [MatthieuHernandez](https://github.com/MatthieuHernandez)
- [Metalsofa](https://github.com/Metalsofa)
- [mrpossoms](https://github.com/mrpossoms)
- [mynameisjohn](https://github.com/mynameisjohn)
- [Sidelobe](https://github.com/Sidelobe)
- [sschaetz](https://github.com/sschaetz)
- [Yhcrown](https://github.com/Yhcrown)

## Want to Contribute?

If you would like to submit a pull request for this library, please do! But kindly follow the following simple guidelines...

* Make the changes as concise as is possible for the change you are proposing
* Avoid unnecessarily changing a large number of lines - e.g. commits changing the number of spaces in indentations on all lines (and so on)
* Keep to the code style of this library which is the [JUCE Coding Standards](https://juce.com/discover/stories/coding-standards)
* Make the changes relative to the develop branch of the library (as this may have advanced beyond the master branch)
- Make the changes as concise as is possible for the change you are proposing
- Avoid unnecessarily changing a large number of lines - e.g. commits changing the number of spaces in indentations on all lines (and so on)
- Keep to the code style of this library which is the [JUCE Coding Standards](https://juce.com/discover/stories/coding-standards)
- Make the changes relative to the develop branch of the library (as this may have advanced beyond the master branch)

License
-------
## License

MIT License

Expand Down

0 comments on commit 1713396

Please sign in to comment.