2. Dealing with multi-channels audio file

[1]:
import pprint

import matplotlib.pyplot as plt

import cutcutcodec

2.1. All supported audio layouts

2.1.1. Layouts and channels signification and convention

[2]:
# all supported layout by cutcutcodec
pprint.pprint(cutcutcodec.classes.layout.AllLayouts().layouts, compact=True)
{'2.1': ('fl', 'fr', 'lfe'),
 '22.2': ('fl', 'fr', 'fc', 'lfe', 'bl', 'br', 'flc', 'frc', 'bc', 'sl', 'sr',
          'tc', 'tfl', 'tfc', 'tfr', 'tbl', 'tbc', 'tbr', 'lfe2', 'tsl', 'tsr',
          'bfc', 'bfl', 'bfr'),
 '3.0': ('fl', 'fr', 'fc'),
 '3.0(back)': ('fl', 'fr', 'bc'),
 '3.1': ('fl', 'fr', 'fc', 'lfe'),
 '3.1.2': ('fl', 'fr', 'fc', 'lfe', 'tfl', 'tfr'),
 '4.0': ('fl', 'fr', 'fc', 'bc'),
 '4.1': ('fl', 'fr', 'fc', 'lfe', 'bc'),
 '5.0': ('fl', 'fr', 'fc', 'bl', 'br'),
 '5.0(side)': ('fl', 'fr', 'fc', 'sl', 'sr'),
 '5.1': ('fl', 'fr', 'fc', 'lfe', 'bl', 'br'),
 '5.1(side)': ('fl', 'fr', 'fc', 'lfe', 'sl', 'sr'),
 '5.1.2': ('fl', 'fr', 'fc', 'lfe', 'sl', 'sr', 'tfl', 'tfr'),
 '5.1.2(back)': ('fl', 'fr', 'fc', 'lfe', 'bl', 'br', 'tfl', 'tfr'),
 '5.1.4': ('fl', 'fr', 'fc', 'lfe', 'sl', 'sr', 'tfl', 'tfr', 'tbl', 'tbr'),
 '6.0': ('fl', 'fr', 'fc', 'bc', 'sl', 'sr'),
 '6.0(front)': ('fl', 'fr', 'flc', 'frc', 'sl', 'sr'),
 '6.1': ('fl', 'fr', 'fc', 'lfe', 'bc', 'sl', 'sr'),
 '6.1(back)': ('fl', 'fr', 'fc', 'lfe', 'bl', 'br', 'bc'),
 '6.1(front)': ('fl', 'fr', 'lfe', 'flc', 'frc', 'sl', 'sr'),
 '7.0': ('fl', 'fr', 'fc', 'bl', 'br', 'sl', 'sr'),
 '7.0(front)': ('fl', 'fr', 'fc', 'flc', 'frc', 'sl', 'sr'),
 '7.1': ('fl', 'fr', 'fc', 'lfe', 'bl', 'br', 'sl', 'sr'),
 '7.1(wide)': ('fl', 'fr', 'fc', 'lfe', 'bl', 'br', 'flc', 'frc'),
 '7.1(wide-side)': ('fl', 'fr', 'fc', 'lfe', 'flc', 'frc', 'sl', 'sr'),
 '7.1.2': ('fl', 'fr', 'fc', 'lfe', 'bl', 'br', 'sl', 'sr', 'tfl', 'tfr'),
 '7.1.4': ('fl', 'fr', 'fc', 'lfe', 'bl', 'br', 'sl', 'sr', 'tfl', 'tfr', 'tbl',
           'tbr'),
 '7.2.3': ('fl', 'fr', 'fc', 'lfe', 'bl', 'br', 'sl', 'sr', 'tfl', 'tfr', 'tbc',
           'lfe2'),
 '9.1.4': ('fl', 'fr', 'fc', 'lfe', 'bl', 'br', 'flc', 'frc', 'sl', 'sr', 'tfl',
           'tfr', 'tbl', 'tbr'),
 '9.1.6': ('fl', 'fr', 'fc', 'lfe', 'bl', 'br', 'flc', 'frc', 'sl', 'sr', 'tfl',
           'tfr', 'tbl', 'tbr', 'tsl', 'tsr'),
 'binaural': ('bil', 'bir'),
 'cube': ('fl', 'fr', 'bl', 'br', 'tfl', 'tfr', 'tbl', 'tbr'),
 'downmix': ('dl', 'dr'),
 'hexadecagonal': ('fl', 'fr', 'fc', 'bl', 'br', 'bc', 'sl', 'sr', 'tfl', 'tfc',
                   'tfr', 'tbl', 'tbc', 'tbr', 'wl', 'wr'),
 'hexagonal': ('fl', 'fr', 'fc', 'bl', 'br', 'bc'),
 'mono': ('fc',),
 'octagonal': ('fl', 'fr', 'fc', 'bl', 'br', 'bc', 'sl', 'sr'),
 'quad': ('fl', 'fr', 'bl', 'br'),
 'quad(side)': ('fl', 'fr', 'sl', 'sr'),
 'stereo': ('fl', 'fr')}
[3]:
# the significance of each channel abreviation
pprint.pprint(cutcutcodec.classes.layout.AllLayouts().individuals)
{'bc': 'back center',
 'bfc': 'bottom front center',
 'bfl': 'bottom front left',
 'bfr': 'bottom front right',
 'bil': 'binaural left',
 'bir': 'binaural right',
 'bl': 'back left',
 'br': 'back right',
 'dl': 'downmix left',
 'dr': 'downmix right',
 'fc': 'front center',
 'fl': 'front left',
 'flc': 'front left-of-center',
 'fr': 'front right',
 'frc': 'front right-of-center',
 'lfe': 'low frequency',
 'lfe2': 'low frequency 2',
 'sdl': 'surround direct left',
 'sdr': 'surround direct right',
 'sl': 'side left',
 'sr': 'side right',
 'ssl': 'side surround left',
 'ssr': 'side surround right',
 'tbc': 'top back center',
 'tbl': 'top back left',
 'tbr': 'top back right',
 'tc': 'top center',
 'tfc': 'top front center',
 'tfl': 'top front left',
 'tfr': 'top front right',
 'tsl': 'top side left',
 'tsr': 'top side right',
 'ttl': 'top surround left',
 'ttr': 'top surround right',
 'wl': 'wide left',
 'wr': 'wide right'}

2.1.2. Audio layout and codec compatibility

[4]:
from cutcutcodec.core.compilation.export.compatibility import Compatibilities

pprint.pprint(Compatibilities().codecs_audio(layout="5.1"), compact=True)
Testing encoder/muxer: 100%|███████████████████████████| 12775/12775 [00:10<00:00, 1234.37comb/s]
{'aac': [('aac', '3g2'), ('aac', '3gp'), ('aac', 'adts'), ('aac', 'asf'),
         ('aac', 'avi'), ('aac', 'f4v'), ('aac', 'flv'), ('aac', 'ipod'),
         ('aac', 'ismv'), ('aac', 'matroska'), ('aac', 'mov'), ('aac', 'mp4'),
         ('aac', 'mpegts'), ('aac', 'nut'), ('aac', 'rm'), ('aac', 'w64'),
         ('aac', 'wav'), ('aac', 'wtv')],
 'aac_latm': [('aac', 'latm')],
 'alac': [('alac', 'caf'), ('alac', 'ipod'), ('alac', 'ismv'),
          ('alac', 'matroska'), ('alac', 'mov'), ('alac', 'mp4')],
 'vorbis': [('libvorbis', 'asf'), ('libvorbis', 'avi'), ('libvorbis', 'ismv'),
            ('libvorbis', 'matroska'), ('libvorbis', 'mp4'),
            ('libvorbis', 'nut'), ('libvorbis', 'oga'), ('libvorbis', 'ogg'),
            ('libvorbis', 'ogv'), ('libvorbis', 'opus'), ('libvorbis', 'spx'),
            ('libvorbis', 'w64'), ('libvorbis', 'wav'), ('libvorbis', 'webm'),
            ('libvorbis', 'wtv')],
 'wavpack': [('wavpack', 'matroska'), ('wavpack', 'nut'), ('wavpack', 'wv')]}

2.2. Create multi-channel streams

[5]:
signal_stereo = cutcutcodec.generation.GeneratorAudioEquation(
    "sin(2*pi*220*t)*sin(2*pi*1*t)**2", "sin(2*pi*220*t)*cos(2*pi*1*t)**2",
)
signal_3_1 = cutcutcodec.generation.GeneratorAudioEquation(
    "sin(2*pi*440*t)",  # fl
    "cos(2*pi*440*t)",  # fr
    "sin(2*pi*523*t)",  # fc
    "sin(2.pi*27.5*t)",  # lfe
    layout="3.1",
)

2.2.1. Combine the channels of the different streams

[6]:
mix = (signal_stereo | signal_3_1).apply_audio_equation(  # mix the channels as a 5.1 layer ('fl', 'fr', 'fc', 'lfe', 'bl', 'br'),
    "(fl_0+fl_1)/2",  # fl
    "(fl_0+fl_1)/2",  # fr
    "0.8*fc_1 + 0.1*fl_0 + 0.1*fr_0",  # fc
    "lfe_1",  # lfe
    "(fl_0+fl_1)/2",  # bl
    "(fr_0+fr_1)/2",  # br
)
(mix_stream,) = mix.out_streams
[7]:
frame = mix_stream.snapshot(0, 44100, 1024)  # time, sample rate, nbr samples
[8]:
plt.plot(frame.timestamps, frame.T)
plt.xlabel("time (s)")
plt.ylabel("amplitude")
plt.title(
    f"{frame.layout.name} audio frame at {frame.rate} Hz "
    f"containing {frame.samples} samples starting at time {frame.time} s",
)
plt.show()
../../../_images/build_examples_advanced_multi_channels_13_0.png

2.3. Write a multichannels audio file

[9]:
mix_cut = mix.apply_audio_subclip(0, 10)  # select the 10 first seconds
cutcutcodec.write(mix_cut.out_streams, "/tmp/audio_5.1.opus", streams_settings=[{"encodec": "libvorbis", "rate": 44100}])
Encoding audio_5.1.opus: 100%|██████████████████████████████████████| 10.00s/10.00s [00:00<00:00]