Hello
I use PsychToolBox to record audio data and play sounds from a sound card. I have multiple slave devices for audio recording, because each slave is dealing with a distinct stream of audio data and I prefer to keep the recording separated into distinct slaves, even though this is not strictly necessary. There is also a slave device dedicated to sound playback.
It is crucial for me that all the slave devices are synchronized, i.e. the timestamps of all slaves belong to the same clock and I can align the different slave audio recordings with each other. Note that the audio recording of all slaves do not need to start simultaneously, I only need them to be in the same clock.
Below is a sample code of how I programmed the audio devices. The code works all fine, but I believe that the slave audio recordings are misaligned.
Question: can I reliably use tCaptureStart1, tCaptureStart2, and tCaptureStart3 to align the three slave audio recordings?
Thank you for any help!
%% Open master device
modeOper = 3+8; % 2 for recording, 3 for simultaneous capture and playback of sound; +8 to open as master device.
reqlatencyclass = 1;
desiredFS = 192000;
nAudioChannels = [6 6];
selectedChannels = [];
% Open master device
devHandleMaster = PsychPortAudio('Open', deviceID, modeOper, reqlatencyclass, desiredFS, nAudioChannels, [],[],selectedChannels);
% Start master immediately, wait for it to be started
PsychPortAudio('Start', devHandleMaster, 0, 0, 1);
% Retrieve status once to get access to SampleRate and other params:
devStatus = PsychPortAudio('GetStatus', sounds.devHandleMaster);
SampleRate = devStatus.SampleRate;
%% Slaves
selectedChannels_slave1 = [1 2 3 4];
nAudioChannels_slave1 = length(selectedChannels_slave1);
devHandleRec_slave1 = PsychPortAudio('OpenSlave', devHandleMaster, 2, nAudioChannels_slave1, selectedChannels_slave1);
% Preallocate internal audio recording buffer:
PsychPortAudio('GetAudioData', devHandleRec_slave1, 10);
selectedChannels_slave2 = [5];
nAudioChannels_slave2 = length(selectedChannels_slave1);
devHandleRec_slave2 = PsychPortAudio('OpenSlave', devHandleMaster, 2, nAudioChannels_slave2, selectedChannels_slave2);
% Preallocate internal audio recording buffer:
PsychPortAudio('GetAudioData', devHandleRec_slave2, 10);
selectedChannels_slave3 = [6];
nAudioChannels_slave3 = length(selectedChannels_slave1);
devHandleRec_slave3 = PsychPortAudio('OpenSlave', devHandleMaster, 2, nAudioChannels_slave3, selectedChannels_slave3);
% Preallocate internal audio recording buffer:
PsychPortAudio('GetAudioData', devHandleRec_slave3, 10);
% Open slave device dedicated to play sounds (modeOper = 1)
nAudioChannels_output = 2;
selectedChannels_Out = [];
devHandlePlay_slave = PsychPortAudio('OpenSlave', devHandleMaster, 1, nAudioChannels_output, selectedChannels_Out);
%% Start audio recording!
waitForStart = 1;
PsychPortAudio('Start', devHandleRec_slave1, [],[],waitForStart);
PsychPortAudio('Start', devHandleRec_slave2, [],[],waitForStart);
PsychPortAudio('Start', devHandleRec_slave3, [],[],waitForStart);
...
% other code runs here
...
%% Get audio data
% I run this section every ~0.1 seconds to get audio data from each slave.
% All the blocks of data for each slave are stitched together to make a
% single, uninterrupted stream of audio data for each slave.
% The whole audio recording last several hours.
singleType = 1;
% Slave 1
[audiodata1, offset1, overflow1, tCaptureStart1] = PsychPortAudio('GetAudioData', devHandleRec_slave1, [],[],[],singleType);
% Get timestamp (system clock, in seconds) of the first sample of this block of data:
TimeStamp_thisBlock1 = tCaptureStart1 + (offset1 / SampleRate);
% Get nr. samples contained in this block of data:
NrSamples_thisBlock1 = size(audiodata1, 2);
% Slave 2
[audiodata2, offset2, overflow2, tCaptureStart2] = PsychPortAudio('GetAudioData', devHandleRec_slave2, [],[],[],singleType);
TimeStamp_thisBlock2 = tCaptureStart2 + (offset2 / SampleRate);
NrSamples_thisBlock2 = size(audiodata2, 2);
% Slave 3
[audiodata3, offset3, overflow3, tCaptureStart3] = PsychPortAudio('GetAudioData', devHandleRec_slave3, [],[],[],singleType);
TimeStamp_thisBlock3 = tCaptureStart3 + (offset3 / SampleRate);
NrSamples_thisBlock3 = size(audiodata3, 2);
...
% other code to save the audio data of each block in binary files
...