Creative Voice File: format specification

Creative Voice File is a container file format for digital audio wave data. Initial revisions were able to support only unsigned 8-bit PCM and ADPCM data, later versions were revised to add support for 16-bit PCM and a-law / u-law formats.

This format was actively used in 1990s, around the advent of Creative's sound cards (Sound Blaster family). It was a popular choice for a digital sound container in lots of games and multimedia software due to simplicity and availability of Creative's recording / editing tools.

File extension

voc

KS implementation details

License: CC0-1.0

References

This page hosts a formal specification of Creative Voice File using Kaitai Struct. This specification can be automatically translated into a variety of programming languages to get a parsing library.

Block diagram

Format specification in Kaitai Struct YAML

meta:
  id: creative_voice_file
  title: Creative Voice File
  file-extension: voc
  xref:
    justsolve: Creative_Voice_File
    mime: audio/x-voc
    wikidata: Q27967410
  license: CC0-1.0
  endian: le
doc: |
  Creative Voice File is a container file format for digital audio
  wave data. Initial revisions were able to support only unsigned
  8-bit PCM and ADPCM data, later versions were revised to add support
  for 16-bit PCM and a-law / u-law formats.

  This format was actively used in 1990s, around the advent of
  Creative's sound cards (Sound Blaster family). It was a popular
  choice for a digital sound container in lots of games and multimedia
  software due to simplicity and availability of Creative's recording
  / editing tools.
doc-ref: 'https://wiki.multimedia.cx/index.php?title=Creative_Voice'
# https://fabiensanglard.net/reverse_engineering_strike_commander/docs/Creative%20Voice%20(VOC)%20file%20format.txt
seq:
  - id: magic
    contents:
      - 'Creative Voice File'
      - 0x1a
  - id: header_size
    type: u2
    doc: Total size of this main header (usually 0x001A)
  - id: version
    type: u2
  - id: checksum
    type: u2
    doc: 'Checksum: this must be equal to ~version + 0x1234'
  - id: blocks
    type: block
    repeat: eos
    doc: Series of blocks that contain the actual audio data
types:
  block:
    seq:
      - id: block_type
        type: u1
        enum: block_types
        doc: Byte that determines type of block content
      - id: body_size1
        type: u2
        if: block_type != block_types::terminator
      - id: body_size2
        type: u1
        if: block_type != block_types::terminator
      - id: body
        size: body_size
        type:
          switch-on: block_type
          cases:
            'block_types::sound_data': block_sound_data
            'block_types::silence': block_silence
            'block_types::marker': block_marker
            #'block_types::text': block_text
            'block_types::repeat_start': block_repeat_start
            #'block_types::repeat_end': always_empty_block
            'block_types::extra_info': block_extra_info
            'block_types::sound_data_new': block_sound_data_new
        if: block_type != block_types::terminator
        doc: Block body, type depends on block type byte
    instances:
      body_size:
        value: body_size1 + (body_size2 << 16)
        if: block_type != block_types::terminator
        doc: |
          body_size is a 24-bit little-endian integer, so we're
          emulating that by adding two standard-sized integers
          (body_size1 and body_size2).
  block_sound_data:
    doc-ref: 'https://wiki.multimedia.cx/index.php?title=Creative_Voice#Block_type_0x01:_Sound_data'
    seq:
      - id: freq_div
        type: u1
        doc: Frequency divisor, used to determine sample rate
      - id: codec
        type: u1
        enum: codecs
      - id: wave
        size-eos: true
    instances:
      sample_rate:
        value: 1000000.0 / (256 - freq_div)
  block_silence:
    doc-ref: 'https://wiki.multimedia.cx/index.php?title=Creative_Voice#Block_type_0x03:_Silence'
    seq:
      - id: duration_samples
        type: u2
        doc: Duration of silence, in samples
      - id: freq_div
        type: u1
        doc: Frequency divisor, used to determine sample rate
    instances:
      sample_rate:
        value: 1000000.0 / (256 - freq_div)
      duration_sec:
        value: duration_samples / sample_rate
        doc: Duration of silence, in seconds
  block_marker:
    doc-ref: 'https://wiki.multimedia.cx/index.php?title=Creative_Voice#Block_type_0x04:_Marker'
    seq:
      - id: marker_id
        type: u2
        doc: Marker ID
  block_repeat_start:
    doc-ref: 'https://wiki.multimedia.cx/index.php?title=Creative_Voice#Block_type_0x06:_Repeat_start'
    seq:
      - id: repeat_count_1
        type: u2
        doc: Number of repetitions minus 1; 0xffff means infinite repetitions
  block_extra_info:
    doc-ref: 'https://wiki.multimedia.cx/index.php?title=Creative_Voice#Block_type_0x08:_Extra_info'
    seq:
      - id: freq_div
        type: u2
        doc: Frequency divisor
      - id: codec
        type: u1
        enum: codecs
      - id: num_channels_1
        type: u1
        doc: Number of channels minus 1 (0 = mono, 1 = stereo)
    instances:
      num_channels:
        value: num_channels_1 + 1
        doc: Number of channels (1 = mono, 2 = stereo)
      sample_rate:
        value: 256000000.0 / (num_channels * (65536 - freq_div))
  block_sound_data_new:
    doc-ref: 'https://wiki.multimedia.cx/index.php?title=Creative_Voice#Block_type_0x09:_Sound_data_.28New_format.29'
    seq:
      - id: sample_rate
        type: u4
      - id: bits_per_sample
        type: u1
      - id: num_channels
        type: u1
      - id: codec
        type: u2
        enum: codecs
      - id: reserved
        size: 4
      - id: wave
        size-eos: true
enums:
  block_types:
    0: terminator
    1: sound_data
    2: sound_data_cont
    3: silence
    4: marker
    5: text
    6: repeat_start
    7: repeat_end
    8: extra_info
    9: sound_data_new
  # https://wiki.multimedia.cx/index.php?title=Creative_Voice#Supported_codec_ids
  codecs:
    0x00: pcm_8bit_unsigned
    0x01: adpcm_4bit # 4 bits to 8 bits Creative ADPCM
    0x02: adpcm_2_6bit # 3 bits to 8 bits Creative ADPCM (AKA 2.6 bits)
    0x03: adpcm_2_bit # 2 bits to 8 bits Creative ADPCM
    0x04: pcm_16bit_signed # 16 bits signed PCM
    0x06: alaw
    0x07: ulaw
    0x0200: adpcm_4_to_16bit # 4 bits to 16 bits Creative ADPCM