Minor changes to AM824 WAV player before merge into master branch

This commit is contained in:
Andrea Bondavalli 2020-08-30 16:16:25 +02:00
parent d7a117e482
commit 344fba0827
7 changed files with 1075 additions and 1010 deletions

157
wavplay_am824/.clang-format Normal file
View File

@ -0,0 +1,157 @@
---
Language: Cpp
# BasedOnStyle: Chromium
AccessModifierOffset: -1
AlignAfterOpenBracket: Align
AlignConsecutiveMacros: false
AlignConsecutiveAssignments: false
AlignConsecutiveDeclarations: false
AlignEscapedNewlines: Left
AlignOperands: true
AlignTrailingComments: true
AllowAllArgumentsOnNextLine: true
AllowAllConstructorInitializersOnNextLine: true
AllowAllParametersOfDeclarationOnNextLine: false
AllowShortBlocksOnASingleLine: false
AllowShortCaseLabelsOnASingleLine: false
AllowShortFunctionsOnASingleLine: Inline
AllowShortLambdasOnASingleLine: All
AllowShortIfStatementsOnASingleLine: Never
AllowShortLoopsOnASingleLine: false
AlwaysBreakAfterDefinitionReturnType: None
AlwaysBreakAfterReturnType: None
AlwaysBreakBeforeMultilineStrings: true
AlwaysBreakTemplateDeclarations: Yes
BinPackArguments: true
BinPackParameters: false
BraceWrapping:
AfterCaseLabel: false
AfterClass: false
AfterControlStatement: false
AfterEnum: false
AfterFunction: false
AfterNamespace: false
AfterObjCDeclaration: false
AfterStruct: false
AfterUnion: false
AfterExternBlock: false
BeforeCatch: false
BeforeElse: false
IndentBraces: false
SplitEmptyFunction: true
SplitEmptyRecord: true
SplitEmptyNamespace: true
BreakBeforeBinaryOperators: None
BreakBeforeBraces: Attach
BreakBeforeInheritanceComma: false
BreakInheritanceList: BeforeColon
BreakBeforeTernaryOperators: true
BreakConstructorInitializersBeforeComma: false
BreakConstructorInitializers: BeforeColon
BreakAfterJavaFieldAnnotations: false
BreakStringLiterals: true
ColumnLimit: 80
CommentPragmas: '^ IWYU pragma:'
CompactNamespaces: false
ConstructorInitializerAllOnOneLineOrOnePerLine: true
ConstructorInitializerIndentWidth: 4
ContinuationIndentWidth: 4
Cpp11BracedListStyle: true
DerivePointerAlignment: false
DisableFormat: false
ExperimentalAutoDetectBinPacking: false
FixNamespaceComments: true
ForEachMacros:
- foreach
- Q_FOREACH
- BOOST_FOREACH
IncludeBlocks: Regroup
IncludeCategories:
- Regex: '^<ext/.*\.h>'
Priority: 2
- Regex: '^<.*\.h>'
Priority: 1
- Regex: '^<.*'
Priority: 2
- Regex: '.*'
Priority: 3
IncludeIsMainRegex: '([-_](test|unittest))?$'
IndentCaseLabels: true
IndentPPDirectives: None
IndentWidth: 2
IndentWrappedFunctionNames: false
JavaScriptQuotes: Leave
JavaScriptWrapImports: true
KeepEmptyLinesAtTheStartOfBlocks: false
MacroBlockBegin: ''
MacroBlockEnd: ''
MaxEmptyLinesToKeep: 1
NamespaceIndentation: None
ObjCBinPackProtocolList: Never
ObjCBlockIndentWidth: 2
ObjCSpaceAfterProperty: false
ObjCSpaceBeforeProtocolList: true
PenaltyBreakAssignment: 2
PenaltyBreakBeforeFirstCallParameter: 1
PenaltyBreakComment: 300
PenaltyBreakFirstLessLess: 120
PenaltyBreakString: 1000
PenaltyBreakTemplateDeclaration: 10
PenaltyExcessCharacter: 1000000
PenaltyReturnTypeOnItsOwnLine: 200
PointerAlignment: Left
RawStringFormats:
- Language: Cpp
Delimiters:
- cc
- CC
- cpp
- Cpp
- CPP
- 'c++'
- 'C++'
CanonicalDelimiter: ''
BasedOnStyle: google
- Language: TextProto
Delimiters:
- pb
- PB
- proto
- PROTO
EnclosingFunctions:
- EqualsProto
- EquivToProto
- PARSE_PARTIAL_TEXT_PROTO
- PARSE_TEST_PROTO
- PARSE_TEXT_PROTO
- ParseTextOrDie
- ParseTextProtoOrDie
CanonicalDelimiter: ''
BasedOnStyle: google
ReflowComments: true
SortIncludes: false
SortUsingDeclarations: true
SpaceAfterCStyleCast: false
SpaceAfterLogicalNot: false
SpaceAfterTemplateKeyword: true
SpaceBeforeAssignmentOperators: true
SpaceBeforeCpp11BracedList: false
SpaceBeforeCtorInitializerColon: true
SpaceBeforeInheritanceColon: true
SpaceBeforeParens: ControlStatements
SpaceBeforeRangeBasedForLoopColon: true
SpaceInEmptyParentheses: false
SpacesBeforeTrailingComments: 2
SpacesInAngles: false
SpacesInContainerLiterals: true
SpacesInCStyleCastParentheses: false
SpacesInParentheses: false
SpacesInSquareBrackets: false
Standard: Auto
StatementMacros:
- Q_UNUSED
- QT_REQUIRE_VERSION
TabWidth: 8
UseTab: Never
...

View File

@ -0,0 +1,8 @@
cmake_minimum_required(VERSION 3.7.0)
project(wavplay_am824 CXX)
set(CMAKE_CXX_FLAGS "-g -Wall")
find_library(PORTAUDIO NAMES portaudio)
find_library(SNDFILE NAMES sndfile)
add_executable(wavplay_am824 wavplay_am824.cpp)
target_link_libraries(wavplay_am824 ${PORTAUDIO})
target_link_libraries(wavplay_am824 ${SNDFILE})

12
wavplay_am824/README.md Normal file
View File

@ -0,0 +1,12 @@
# AM824 WAV player
## Prerequisite ##
The player requires PortAudio and libsndfile libraries.
The [ubuntu-packages.sh](ubuntu-packages.sh) script can be used to install all the required packages on ubuntu distros.
## Build ##
To build run:
cmake .
make

View File

@ -15,7 +15,6 @@
* along with this program. If not, see <http://www.gnu.org/licenses/> * along with this program. If not, see <http://www.gnu.org/licenses/>
************************************************************************************************************/ ************************************************************************************************************/
#include <stdint.h> #include <stdint.h>
#define CHANNEL_STATUS_BYTES 24 #define CHANNEL_STATUS_BYTES 24
@ -24,14 +23,22 @@
#define BOTTOMBIT 1 #define BOTTOMBIT 1
#define REFLECTED_POLYNOMIAL 0xb8 // Unreflected is 0x1d #define REFLECTED_POLYNOMIAL 0xb8 // Unreflected is 0x1d
enum AM824ErrorCode{ AM824_ERR_OK = 0, AM824_ERR_BAD_SAMPLING_FREQUENCY = -1, AM824_ERR_UNSUPPORTED_BITDEPTH = -2 }; enum AM824ErrorCode {
AM824_ERR_OK = 0,
AM824_ERR_BAD_SAMPLING_FREQUENCY = -1,
AM824_ERR_UNSUPPORTED_BITDEPTH = -2
};
enum AM824SamplingFrequency { FS_NOT_INDICATED = 0, FS_44100_HZ = 1, FS_48000_HZ = 2, FS_32000_HZ = 3 }; enum AM824SamplingFrequency {
FS_NOT_INDICATED = 0,
FS_44100_HZ = 1,
FS_48000_HZ = 2,
FS_32000_HZ = 3
};
enum AM824Endianess { AM824_BIG_ENDIAN, AM824_LITTLE_ENDIAN }; enum AM824Endianess { AM824_BIG_ENDIAN, AM824_LITTLE_ENDIAN };
class AM824Framer class AM824Framer {
{
uint8_t channelStatusIndex; uint8_t channelStatusIndex;
uint8_t channelStatusMask; uint8_t channelStatusMask;
uint8_t channelStatus[CHANNEL_STATUS_BYTES]; uint8_t channelStatus[CHANNEL_STATUS_BYTES];
@ -41,62 +48,53 @@ class AM824Framer
uint8_t crcTable[256]; uint8_t crcTable[256];
AM824Endianess endian; AM824Endianess endian;
static uint8_t getParity(unsigned int n) static uint8_t getParity(unsigned int n) {
{
uint8_t parity = 0; uint8_t parity = 0;
while (n) while (n) {
{
parity = 1 - parity; parity = 1 - parity;
n = n & (n - 1); n = n & (n - 1);
} }
return parity; return parity;
} }
void crcTableInit(void) void crcTableInit(void) {
{
uint8_t remainder; uint8_t remainder;
for (int dividend = 0; dividend < 256; ++dividend) for (int dividend = 0; dividend < 256; ++dividend) {
{
remainder = dividend << (WIDTH - 8); remainder = dividend << (WIDTH - 8);
for (uint8_t bit = 0; bit < 8; bit++) for (uint8_t bit = 0; bit < 8; bit++) {
{ if (remainder & BOTTOMBIT) {
if (remainder & BOTTOMBIT)
{
remainder = (remainder >> 1) ^ REFLECTED_POLYNOMIAL; remainder = (remainder >> 1) ^ REFLECTED_POLYNOMIAL;
} } else {
else
{
remainder = (remainder >> 1); remainder = (remainder >> 1);
} }
} }
crcTable[dividend] = remainder; crcTable[dividend] = remainder;
} }
} }
void setCRC(void) void setCRC(void) {
{
uint8_t data; uint8_t data;
uint8_t remainder = 0xff; uint8_t remainder = 0xff;
for (int byte = 0; byte < 23; byte++) for (int byte = 0; byte < 23; byte++) {
{
data = channelStatus[byte] ^ remainder; data = channelStatus[byte] ^ remainder;
remainder = crcTable[data]; remainder = crcTable[data];
} }
channelStatus[23] = remainder; channelStatus[23] = remainder;
} }
public:
public:
// Input number of channels and the bitdepth of the input samples // Input number of channels and the bitdepth of the input samples
// Note that the output bit depth is always 24 bit // Note that the output bit depth is always 24 bit
AM824Framer(uint8_t newNumChannels, /* Input - Number of channels of input/output audio */ AM824Framer(
uint8_t newBitDepth, /* Input - Bit depth of input audio, output is always 32 bit */ uint8_t
AM824Endianess outputEndianess, /* Input = Endianess of output samples, input is always machine order */ newNumChannels, /* Input - Number of channels of input/output audio */
AM824ErrorCode &err) /* Output - error code */ uint8_t newBitDepth, /* Input - Bit depth of input audio, output is always
32 bit */
AM824Endianess outputEndianess, /* Input = Endianess of output samples,
input is always machine order */
AM824ErrorCode& err) /* Output - error code */
{ {
uint8_t i; uint8_t i;
channelStatusIndex = 0; channelStatusIndex = 0;
@ -108,8 +106,7 @@ public:
endian = outputEndianess; endian = outputEndianess;
// Set certain channel status bits // Set certain channel status bits
// Clear it first // Clear it first
for (i = 0 ; i < CHANNEL_STATUS_BYTES ; i++) for (i = 0; i < CHANNEL_STATUS_BYTES; i++) {
{
channelStatus[i] = 0; channelStatus[i] = 0;
} }
// Default Channel Status // Default Channel Status
@ -120,8 +117,7 @@ public:
// 48kHz // 48kHz
channelStatus[0] |= 2 << 6; channelStatus[0] |= 2 << 6;
switch(bitDepth) switch (bitDepth) {
{
case 16: case 16:
channelStatus[2] |= 1 << 3; channelStatus[2] |= 1 << 3;
break; break;
@ -146,68 +142,57 @@ public:
err = AM824_ERR_OK; err = AM824_ERR_OK;
} }
AM824ErrorCode setSamplingFrequency(AM824SamplingFrequency fs_code) AM824ErrorCode setSamplingFrequency(AM824SamplingFrequency fs_code) {
{ if (fs_code > FS_32000_HZ) {
if (fs_code > FS_32000_HZ) return (AM824_ERR_BAD_SAMPLING_FREQUENCY);
{
return(AM824_ERR_BAD_SAMPLING_FREQUENCY);
} }
// Reset top two bits and set accordingly // Reset top two bits and set accordingly
channelStatus[0] &= 0x3f; channelStatus[0] &= 0x3f;
channelStatus[0] |= fs_code << 6; channelStatus[0] |= fs_code << 6;
setCRC(); setCRC();
return(AM824_ERR_OK); return (AM824_ERR_OK);
} }
void setProfessionalMode(void) void setProfessionalMode(void) {
{
channelStatus[0] |= 1; channelStatus[0] |= 1;
setCRC(); setCRC();
} }
void setConsumerMode(void) void setConsumerMode(void) {
{
channelStatus[0] &= 0xfe; channelStatus[0] &= 0xfe;
setCRC(); setCRC();
} }
void setAudioMode(void) void setAudioMode(void) {
{
channelStatus[0] &= 0xfd; channelStatus[0] &= 0xfd;
setCRC(); setCRC();
} }
void setDataMode(void) void setDataMode(void) {
{
channelStatus[0] |= 2; channelStatus[0] |= 2;
setCRC(); setCRC();
} }
void getAM824Sample(uint32_t inputSample, uint8_t *outputBytes) void getAM824Sample(uint32_t inputSample, uint8_t* outputBytes) {
{
uint32_t outputSample; uint32_t outputSample;
bool channelStatusBit = channelStatus[channelStatusIndex] & channelStatusMask; bool channelStatusBit =
channelStatus[channelStatusIndex] & channelStatusMask;
bool userBit = false; bool userBit = false;
bool validityBit = false; bool validityBit = false;
// Input samples are MSB justified as per AES3 // Input samples are MSB justified as per AES3
if (bitDepth == 16) if (bitDepth == 16) {
{
outputSample = inputSample << 8; outputSample = inputSample << 8;
} } else {
else
{
outputSample = inputSample; outputSample = inputSample;
} }
// Detect block start // Detect block start
if ((channelStatusIndex == 0) && (channelStatusMask == 1)) if ((channelStatusIndex == 0) && (channelStatusMask == 1)) {
{
outputSample |= 1 << 29; outputSample |= 1 << 29;
} }
// Detect frame start // Detect frame start
if (subFrameCounter == 0) if (subFrameCounter == 0) {
{
outputSample |= 1 << 28; outputSample |= 1 << 28;
} }
@ -219,37 +204,30 @@ public:
outputSample |= getParity(outputSample) << 27; outputSample |= getParity(outputSample) << 27;
// Now complete all the wraparound checks // Now complete all the wraparound checks
// Note that channel status chan be different for the different subframes (channels) // Note that channel status chan be different for the different subframes
// but in this example channel status is set to be the same for all subframes (channels) // (channels) but in this example channel status is set to be the same for
// all subframes (channels)
subFrameCounter++; subFrameCounter++;
if (subFrameCounter == numChannels) if (subFrameCounter == numChannels) {
{
subFrameCounter = 0; subFrameCounter = 0;
// Move to next channel status bit // Move to next channel status bit
if (channelStatusMask == 0x80) if (channelStatusMask == 0x80) {
{
channelStatusMask = 1; channelStatusMask = 1;
channelStatusIndex++; channelStatusIndex++;
if (channelStatusIndex == CHANNEL_STATUS_BYTES) if (channelStatusIndex == CHANNEL_STATUS_BYTES) {
{
channelStatusIndex = 0; channelStatusIndex = 0;
} }
} } else {
else
{
channelStatusMask = channelStatusMask << 1; channelStatusMask = channelStatusMask << 1;
} }
} }
if (endian == AM824_BIG_ENDIAN) if (endian == AM824_BIG_ENDIAN) {
{
// Return in 32 bit Big Endian format // Return in 32 bit Big Endian format
*outputBytes++ = (outputSample & 0xff000000) >> 24; *outputBytes++ = (outputSample & 0xff000000) >> 24;
*outputBytes++ = (outputSample & 0x00ff0000) >> 16; *outputBytes++ = (outputSample & 0x00ff0000) >> 16;
*outputBytes++ = (outputSample & 0x0000ff00) >> 8; *outputBytes++ = (outputSample & 0x0000ff00) >> 8;
*outputBytes++ = (outputSample & 0x000000ff) >> 0; *outputBytes++ = (outputSample & 0x000000ff) >> 0;
} } else {
else
{
// Return in 32 bit Little Endian format // Return in 32 bit Little Endian format
*outputBytes++ = (outputSample & 0x000000ff) >> 0; *outputBytes++ = (outputSample & 0x000000ff) >> 0;
*outputBytes++ = (outputSample & 0x0000ff00) >> 8; *outputBytes++ = (outputSample & 0x0000ff00) >> 8;
@ -260,11 +238,9 @@ public:
/* Simple test code to check CRC implementation */ /* Simple test code to check CRC implementation */
/* See EBU Tech 3250 or AES3 for the reference for these examples */ /* See EBU Tech 3250 or AES3 for the reference for these examples */
void testCRC(void) void testCRC(void) {
{
unsigned int i; unsigned int i;
for (i = 0 ; i < CHANNEL_STATUS_BYTES ; i++) for (i = 0; i < CHANNEL_STATUS_BYTES; i++) {
{
channelStatus[i] = 0; channelStatus[i] = 0;
} }
// From AES3-2-2009-r2019 - Example 1 // From AES3-2-2009-r2019 - Example 1
@ -272,26 +248,21 @@ public:
channelStatus[1] = 2; channelStatus[1] = 2;
channelStatus[4] = 2; channelStatus[4] = 2;
setCRC(); setCRC();
if (channelStatus[23] == 0x9b) if (channelStatus[23] == 0x9b) {
{
printf("Example 1 - passed\n"); printf("Example 1 - passed\n");
} } else {
else printf("Example 1 - failed, expecting 0x9b, got 0x%x\n",
{ channelStatus[23]);
printf("Example 1 - failed, expecting 0x9b, got 0x%x\n",channelStatus[23]);
} }
channelStatus[0] = 0x01; channelStatus[0] = 0x01;
channelStatus[1] = 0; channelStatus[1] = 0;
channelStatus[4] = 0; channelStatus[4] = 0;
setCRC(); setCRC();
if (channelStatus[23] == 0x32) if (channelStatus[23] == 0x32) {
{
printf("Example 2 - passed\n"); printf("Example 2 - passed\n");
} } else {
else printf("Example 2 - failed, expecting 0x32, got 0x%x\n",
{ channelStatus[23]);
printf("Example 2 - failed, expecting 0x32, got 0x%x\n",channelStatus[23]);
} }
} }
}; };

View File

@ -0,0 +1,9 @@
#!/bin/bash
#
# Tested on Ubuntu 18.04
#
sudo apt update
sudo apt-get install -y libsndfile1-dev
sudo apt-get install -y libportaudio2
sudo apt-get install -y sox

File diff suppressed because it is too large Load Diff