Generating Multichannel Audio

This example shows how to set up continuous audio generation using multiple audio channels. The signal, a sample of Handel's "Hallelujah Chorus", is broken up into contiguous segments and played back in two parts. The first part of the example plays each segment on a single speaker and a sub-woofer. The second part plays each segment on a different set of speakers (a choir of voices).

Load Audio Data

Load Handel's "Hallelujah".

Load variables:

  • y representing the Hallelujah waveform

  • Fs representing the sampling frequency

load handel;

Create a Data Acquisition

Create a DataAcquisition object using directsound as the vendor ID.

dq = daq("directsound")

Add Channels and Adjust Generation Scan Rate to Match the Audio Sampling Frequency

Add six audio output channels and set the generation scan rate to the audio sampling rate.

addoutput(dq,"Audio7",1:6,"Audio");
dq.Rate = Fs;

Plot Audio Data

Visually identify audio segments that correspond to each "Hallelujah" in the chorus and select sample numbers at which these segments start and stop. Each color in the plot corresponds to a different segment of the chorus.

Identify the End of Each Segment

Visually identify the segment boundaries and mark them.

segmentEnd = [20000, 36000, 45000, 55000, length(y)];

Define Speaker Parameters

Set up a selection of speakers in a cell array named speakerselection to play five segments of "Hallelujah" on six different speakers.

nspeakers = 6;
nspeakergroups = 5;
speakerselection = cell(1, nspeakergroups);

Assign Speakers to Groups

Each speaker selection specifies which speakers from the 5.1 channel speaker system play each audio segment (these assignments may vary for your speaker system). For the first part of the example, use single speakers paired with the sub-woofer (4).

  • Speaker 1: Left-Front

  • Speaker 2: Right-Front

  • Speaker 3: Center

  • Speaker 4: Sub-Woofer

  • Speaker 5: Left-Rear

  • Speaker 6: Right-Rear

speakerselection{1} = [4, 6]; 
% Segment 1; speakers 4 and 6
speakerselection{2} = [4, 5];
% Segment 2; speakers 4 and 5
speakerselection{3} = [1, 4];
% Segment 3; speakers 1 and 4
speakerselection{4} = [2, 4];
% Segment 4; speakers 2 and 4
speakerselection{5} = [3, 4];
% Segment 5; speakers 3 and 4

[singleChannelOutputs] = ...
    surroundSoundVoices(y, segmentEnd, nspeakers, nspeakergroups, speakerselection);

Write Single Channel Outputs

Write a sequence of single channel outputs and then pause before proceeding to the next section.

write(dq, singleChannelOutputs);
pause(3);

Assign Speakers to Groups

Each speaker selection specifies which speakers from the 5.1 channel speaker system play each audio segment (these assignments may vary for your speaker system). For the second part of the example, use groups of speakers. Note that the sub-woofer (4) is included in all speaker selections

  • Speaker 1: Left-Front

  • Speaker 2: Right-Front

  • Speaker 3: Center

  • Speaker 4: Sub-Woofer

  • Speaker 5: Left-Rear

  • Speaker 6: Right-Rear

speakerselection{1} = [4, 5, 6];          % Segment 1; speakers 4, 5, 6
speakerselection{2} = [1, 2, 4];          % Segment 2; speakers 1, 2, 4
speakerselection{3} = [3, 4];             % Segment 3; speakers 3, 4
speakerselection{4} = [1, 2, 3, 4];       % Segment 4; speakers 1, 2, 3, 4
speakerselection{5} = [1, 2, 3, 4, 5, 6]; % Segment 5; all speakers

[multiChannelOutput] = ...
    surroundSoundVoices(y, segmentEnd, nspeakers, nspeakergroups, speakerselection);

Write Multichannel Outputs

write(dq, multiChannelOutput);
function [multiChannelOutput] = surroundSoundVoices(audioOut, segmentEnds, numSpeakers, numSpeakerGroups, speakerGroups)
% Distribute contiguous segments of an output waveform to multiple groups 
% of speakers in a one-to-one relationship. The input waveform is broken up 
% into contiguous segments. Each segment is output by one and only one 
% group of speakers, with each group being visited in turn.

% Break up the input waveform into segments to be played by various groups
% of speakers. In this demonstration, we would like to slowly add "voices"
% by incrementally having more speakers generate the output waveform.
% In particular, we will regard the output waveform as a contiguous
% sequence of segments (one segment per group of speakers). For example, if
% we have 3 groups of speakers, we can think of breaking up the output
% waveform into 3 segments: output = [s1 s2 s3]
% Speaker group 1 outputs: s1 0  0
% Speaker group 2 outputs: 0  s2 0
% Speaker group 3 outputs: 0  0  s3

multiChannelOutput = repmat(0.01, length(audioOut), numSpeakers);
startOfSegment = [1 (segmentEnds(1:end-1)+1)];

for i = 1:numSpeakerGroups
    speakergroup = speakerGroups{i};
    n = numel(speakergroup);
    for j = 1:n
        range = startOfSegment(i):segmentEnds(i);
        multiChannelOutput(range, speakergroup(j)) = audioOut(range);
    end
end

end