Skip to content

Commit

Permalink
GitHub issue #15 - create new metadata item to identify non-Microsoft…
Browse files Browse the repository at this point in the history
… channels
  • Loading branch information
dbry committed Sep 25, 2016
1 parent b7f3e30 commit 1a1210e
Show file tree
Hide file tree
Showing 8 changed files with 268 additions and 77 deletions.
190 changes: 115 additions & 75 deletions cli/caff.c

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion cli/wvparser.c
Expand Up @@ -120,7 +120,7 @@ static const char *metadata_names [] = {
"DUMMY", "ENCODER_INFO", "DECORR_TERMS", "DECORR_WEIGHTS", "DECORR_SAMPLES", "ENTROPY_VARS", "HYBRID_PROFILE", "SHAPING_WEIGHTS",
"FLOAT_INFO", "INT32_INFO", "WV_BITSTREAM", "WVC_BITSTREAM", "WVX_BITSTREAM", "CHANNEL_INFO", "DSD_BLOCK", "UNASSIGNED",
"UNASSIGNED", "RIFF_HEADER", "RIFF_TRAILER", "ALT_HEADER", "ALT_TRAILER", "CONFIG_BLOCK", "MD5_CHECKSUM", "SAMPLE_RATE",
"ALT_EXTENSION", "ALT_MD5_CHECKSUM", "NEW_CONFIG", "UNASSIGNED", "UNASSIGNED", "UNASSIGNED", "UNASSIGNED", "BLOCK_CHECKSUM"
"ALT_EXTENSION", "ALT_MD5_CHECKSUM", "NEW_CONFIG", "CHANNEL_IDENTITIES", "UNASSIGNED", "UNASSIGNED", "UNASSIGNED", "BLOCK_CHECKSUM"
};

static int32_t read_bytes (void *buff, int32_t bcount);
Expand Down
2 changes: 2 additions & 0 deletions include/wavpack.h
Expand Up @@ -351,6 +351,7 @@ int WavpackGetChannelMask (WavpackContext *wpc);
int WavpackGetReducedChannels (WavpackContext *wpc);
int WavpackGetFloatNormExp (WavpackContext *wpc);
int WavpackGetMD5Sum (WavpackContext *wpc, unsigned char data [16]);
void WavpackGetChannelIdentities (WavpackContext *wpc, unsigned char *identities);
uint32_t WavpackGetChannelLayout (WavpackContext *wpc, unsigned char *reorder);
uint32_t WavpackGetWrapperBytes (WavpackContext *wpc);
unsigned char *WavpackGetWrapperData (WavpackContext *wpc);
Expand Down Expand Up @@ -385,6 +386,7 @@ void WavpackSetFileInformation (WavpackContext *wpc, char *file_extension, unsig
int WavpackSetConfiguration (WavpackContext *wpc, WavpackConfig *config, uint32_t total_samples);
int WavpackSetConfiguration64 (WavpackContext *wpc, WavpackConfig *config, int64_t total_samples);
int WavpackSetChannelLayout (WavpackContext *wpc, uint32_t layout_tag, const unsigned char *reorder);
int WavpackSetChannelIdentities (WavpackContext *wpc, const unsigned char *identities);
int WavpackAddWrapper (WavpackContext *wpc, void *data, uint32_t bcount);
int WavpackStoreMD5Sum (WavpackContext *wpc, unsigned char data [16]);
int WavpackPackInit (WavpackContext *wpc);
Expand Down
43 changes: 43 additions & 0 deletions src/common_utils.c
Expand Up @@ -292,6 +292,13 @@ double WavpackGetInstantBitrate (WavpackContext *wpc)
// then that much space must be allocated. Note that all the reordering is actually done
// outside of this library, and that if reordering is done then the appropriate qmode bit
// will be set.
//
// Note: Normally this function would not be used by an application unless it specifically
// wanted to restore a non-standard channel order (to check an MD5, for example) or obtain
// the Core Audio channel layout ID. For simple file decoding for playback, the channel_mask
// should provide all the information required unless there are non-Microsoft channels
// involved, in which case WavpackGetChannelIdentities() will provide the identities of
// the other channels (if they are known).

uint32_t WavpackGetChannelLayout (WavpackContext *wpc, unsigned char *reorder)
{
Expand All @@ -301,6 +308,42 @@ uint32_t WavpackGetChannelLayout (WavpackContext *wpc, unsigned char *reorder)
return wpc->channel_layout;
}

// This function provides the identities of ALL the channels in the file, including the
// standard Microsoft channels (which come first, in order, and are numbered 1-18) and also
// any non-Microsoft channels (which can be in any order and have values from 33-254). The
// value 0x00 is not allowed (but the string is NOT NULL terminated) and 0xFF indicates an
// "unknown" or "unnassigned" channel. The caller must supply enough space for the number
// of channels indicated by WavpackGetNumChannels().
//
// Note that this function returns the actual order of the channels in the Wavpack file
// (i.e., the order returned by WavpackUnpackSamples()). If the file includes a "reordering"
// string because the source file was not in Microsoft order that is NOT taken into account
// here and really only needs to be considered if doing an MD5 verification or if it's
// required to restore the original order/file (like wvunpack does).

void WavpackGetChannelIdentities (WavpackContext *wpc, unsigned char *identities)
{
int num_channels = wpc->config.num_channels, index = 1;
uint32_t channel_mask = wpc->config.channel_mask;
unsigned char *src = wpc->channel_identities;

while (num_channels--) {
if (channel_mask) {
while (!(channel_mask & 1)) {
channel_mask >>= 1;
index++;
}

*identities++ = index++;
channel_mask >>= 1;
}
else if (src && *src)
*identities++ = *src++;
else
*identities++ = 0xff;
}
}

// Close the specified WavPack file and release all resources used by it.
// Returns NULL.

Expand Down
20 changes: 20 additions & 0 deletions src/open_utils.c
Expand Up @@ -485,6 +485,23 @@ static int read_channel_info (WavpackContext *wpc, WavpackMetadata *wpmd)
return TRUE;
}

// Read multichannel identity information from metadata. Data is an array of
// unsigned characters representing any channels in the file that DO NOT
// match one the 18 Microsoft standard channels (and are represented in the
// channel mask). A value of 0 is not allowed and 0xff means an unknown or
// undefined channel identity.

static int read_channel_identities (WavpackContext *wpc, WavpackMetadata *wpmd)
{
if (!wpc->channel_identities) {
wpc->channel_identities = malloc (wpmd->byte_length + 1);
memcpy (wpc->channel_identities, wpmd->data, wpmd->byte_length);
wpc->channel_identities [wpmd->byte_length] = 0;
}

return TRUE;
}

// Read configuration information from metadata.

static int read_config_info (WavpackContext *wpc, WavpackMetadata *wpmd)
Expand Down Expand Up @@ -700,6 +717,9 @@ static int process_metadata (WavpackContext *wpc, WavpackMetadata *wpmd)
case ID_CHANNEL_INFO:
return read_channel_info (wpc, wpmd);

case ID_CHANNEL_IDENTITIES:
return read_channel_identities (wpc, wpmd);

case ID_CONFIG_BLOCK:
return read_config_info (wpc, wpmd);

Expand Down
19 changes: 19 additions & 0 deletions src/pack.c
Expand Up @@ -336,6 +336,19 @@ static void write_channel_info (WavpackContext *wpc, WavpackMetadata *wpmd)
wpmd->byte_length = (int32_t)(byteptr - (char *) wpmd->data);
}

// Allocate room for and copy the multichannel identities into the specified
// metadata structure. Data is an array of unsigned characters representing
// any channels in the file that DO NOT match one the 18 Microsoft standard
// channels (and are represented in the channel mask). A value of 0 is not
// allowed and 0xff means an unknown or undefined channel identity.

static void write_channel_identities_info (WavpackContext *wpc, WavpackMetadata *wpmd)
{
wpmd->byte_length = strlen (wpc->channel_identities);
wpmd->data = strdup (wpc->channel_identities);
wpmd->id = ID_CHANNEL_IDENTITIES;
}

// Allocate room for and copy the configuration information into the specified
// metadata structure. Currently, we just store the upper 3 bytes of
// config.flags and only in the first block of audio data. Note that this is
Expand Down Expand Up @@ -866,6 +879,12 @@ void send_general_metadata (WavpackContext *wpc)
write_channel_info (wpc, &wpmd);
copy_metadata (&wpmd, wps->blockbuff, wps->blockend);
free_metadata (&wpmd);

if (wpc->channel_identities) {
write_channel_identities_info (wpc, &wpmd);
copy_metadata (&wpmd, wps->blockbuff, wps->blockend);
free_metadata (&wpmd);
}
}

if ((flags & INITIAL_BLOCK) && !wps->sample_index) {
Expand Down
66 changes: 66 additions & 0 deletions src/pack_utils.c
Expand Up @@ -333,6 +333,11 @@ int WavpackSetConfiguration64 (WavpackContext *wpc, WavpackConfig *config, int64
// then the appropriate qmode bit must be set to ensure that any MD5 sum is stored with a new
// ID so that old decoders don't try to verify it (and to let the decoder know that a reorder
// might be required).
//
// Note: This function should only be used to encode Core Audio files in such a way that a
// verbatim archive can be created. Applications can just call WavpackSetChannelIdentities()
// if there are non-Microsoft channels to specify, or neither of these functions if only
// Microsoft channels are present.

int WavpackSetChannelLayout (WavpackContext *wpc, uint32_t layout_tag, const unsigned char *reorder)
{
Expand Down Expand Up @@ -365,6 +370,67 @@ int WavpackSetChannelLayout (WavpackContext *wpc, uint32_t layout_tag, const uns
return TRUE;
}

// This function allows setting the identities of any channels that are NOT standard
// Microsoft channels and are therefore not represented in the channel mask. WavPack
// files require that all the Microsoft channels come first (and in Microsoft order)
// and these are followed by any other channels (which can be in any order).
//
// The identities are provided in a NULL-terminated string (0x00 is not an allowed
// channel ID). The Microsoft channels may be provided as well (and will be checked)
// but it is really only neccessary to provide the "unknown" channels. Any truly
// unknown channels are indicated with a 0xFF. A return value of FALSE indicates
// something is wrong with the string.
//
// The channel IDs so far reserved are listed here:
//
// 0: not allowed / terminator
// 1 - 18: Microsoft standard channels
// 30, 31: Stereo mix from RF64 (not really recommended, but RF64 specifies this)
// 33 - 44: Core Audio channels (see Core Audio specification)
// 200 - 207: Core Audio channels (see Core Audio specification)
// 221 - 224: Core Audio channels 301 - 305 (offset by 80)
// 255: Present but unknown or unused channel
//
// All other channel IDs are reserved, but some will be filled in with VST3 and
// Adobe Amio values soon.

int WavpackSetChannelIdentities (WavpackContext *wpc, const unsigned char *identities)
{
const unsigned char *sptr = identities;
int lastchan = 0;

if (wpc->channel_identities) { // free any existing string (should not really happen)
free (wpc->channel_identities);
wpc->channel_identities = NULL;
}

if (!identities) // specifying NULL is okay (but not really required)
return TRUE;

if (strlen (identities) > wpc->config.num_channels) // can't be more than num channels!
return FALSE;

// skip past channels that are specified in the channel mask (no reason to store those)

while (*sptr)
if (*sptr <= 32 && *sptr > lastchan && (wpc->config.channel_mask & (1 << *sptr)))
lastchan = *sptr++;
else
break;

identities = sptr;

// now scan the string for an actually defined channel (and don't store if there aren't any)

while (*sptr)
if (*sptr++ != 0xff) {
wpc->channel_identities = strdup (identities);
break;
}

return TRUE;
}

// Prepare to actually pack samples by determining the size of the WavPack
// blocks and allocating sample buffers and initializing each stream. Call
// after WavpackSetConfiguration() and before WavpackPackSamples(). A return
Expand Down
3 changes: 2 additions & 1 deletion src/wavpack_local.h
Expand Up @@ -254,6 +254,7 @@ typedef struct {
#define ID_ALT_EXTENSION (ID_OPTIONAL_DATA | 0x8)
#define ID_ALT_MD5_CHECKSUM (ID_OPTIONAL_DATA | 0x9)
#define ID_NEW_CONFIG_BLOCK (ID_OPTIONAL_DATA | 0xa)
#define ID_CHANNEL_IDENTITIES (ID_OPTIONAL_DATA | 0xb)
#define ID_BLOCK_CHECKSUM (ID_OPTIONAL_DATA | 0xf)

///////////////////////// WavPack Configuration ///////////////////////////////
Expand Down Expand Up @@ -500,7 +501,7 @@ typedef struct {
void *stream3;

// these items were added in 5.0 to support alternate file types (especially CAF & DSD)
unsigned char file_format, *channel_reordering;
unsigned char file_format, *channel_reordering, *channel_identities;
uint32_t channel_layout, dsd_multiplier;
void *decimation_context;
char file_extension [8];
Expand Down

0 comments on commit 1a1210e

Please sign in to comment.