function AudioTunnel3DDemo % AudioTunnel3DDemo -- A very sketchy and raw demo of how to use OpenAL to % create the illusion of walking through a tunnel which has different sound % sources attached to it. % % You'll need a properly configured multi-speaker system or very good % head-phones attached to a very good soundcard and a lot of luck and % goodwill for this to sound good. % % OpenAL for Matlab is currently only supported on a subset of platforms, % so this demo may abort quickly with an error. % walkthroughduration = 15; walkspeed = -6; zcorridorlength = abs( walkspeed * walkthroughduration ); nsources = 5; % Establish key mapping: ESCape aborts, Space toggles between auto- % movement of sound source or user mouse controlled movement: KbName('UnifyKeynames'); space = KbName('space'); esc = KbName('ESCAPE'); % Initialize OpenAL subsystem at debuglevel 2 with the default output device: InitializeMatlabOpenAL(2); % Generate one sound buffer: buffers = alGenBuffers(nsources); % Query for errors: alGetString(alGetError) % Try to load some impressive sound... sounddir = [PsychtoolboxRoot 'PsychDemos/SoundFiles/']; soundfiles = dir([sounddir '*.wav']); % Velocity of listener: Walks straight down the z-axis: alListenerfv(AL.VELOCITY, [0, 0, walkspeed]); % Start position of listener is at the beginning of the corridor: startpos = - 1.5 * zcorridorlength; if walkspeed < 0 startpos = -startpos; end alListenerfv(AL.POSITION, [0, 0, startpos]); if IsOSX alcASASetListener(ALC.ASA_REVERB_ON, 1); alcASASetListener(ALC.ASA_REVERB_QUALITY, ALC.ASA_REVERB_QUALITY_Max); alcASASetListener(ALC.ASA_REVERB_ROOM_TYPE, ALC.ASA_REVERB_ROOM_TYPE_Cathedral); end % Create a sound source: sources = alGenSources(nsources); perm = randperm(nsources); for i=1:nsources % Assign next soundfilename round-robin: soundname = [sounddir soundfiles(mod(perm(i), length(soundfiles))+1).name]; % Load it... [mynoise freq]= psychwavread(soundname); % Convert it... mynoise = int16(mynoise * 32767); % Fill our sound buffer with the data from the sound vector. Tell AL that its % a 16 bpc, mono format, with length(mynoise)*2 bytes total, to be played at % a sampling rate of freq Hz. The AL will resample this to the native device % sampling rate and format at buffer load time. alBufferData( buffers(i), AL.FORMAT_MONO16, mynoise, length(mynoise)*2, freq); % Attach our buffer to it: The source will play the buffers sound data. alSourceQueueBuffers(sources(i), 1, buffers(i)); % Switch source to looping playback: It will repeat playing the buffer until % its stopped. alSourcei(sources(i), AL.LOOPING, AL.TRUE); % Set emission volume to 100%, aka a gain of 1.0: alSourcef(sources(i), AL.GAIN, 1); alSourcef(sources(i), AL.CONE_INNER_ANGLE, 30); alSourcef(sources(i), AL.CONE_OUTER_ANGLE, 270); alSource3f(sources(i), AL.DIRECTION, 0, 0, 1); % Set position: Nicely lined up in z direction, but randomly placed in % x,y direction within a range of +/- 5 meters: % theta = rand * 2 * pi; % x = cos(theta) * 2; % y = sin(theta) * 2; y = 0; x = mod(i,2) * 8 - 4; % nsources, equally spaced along a sound corridor of zcorridorlength % meters, the first one at z == 0. z = (i-1) * (zcorridorlength / nsources); alSource3f(sources(i), AL.POSITION, x, y, z); % Sources themselves remain static in space: alSource3f(sources(i), AL.VELOCITY, 0, 0, 0); if IsOSX % Source emits some sound that gets reverbrated in room: alcASASetSource(ALC.ASA_REVERB_SEND_LEVEL, sources(i), 0.5); end end % Start playback for these sources: alSourcePlayv(nsources, sources); % 3D sound animation loop. Runs until ESCape key press: manual = 0; tstart = GetSecs; zposition = startpos; while 1 % Check keyboard: [isdown dummy, keycode]=KbCheck; if isdown if keycode(esc) break; end if keycode(space) % Toggle between mouse control and automatic: manual=1-manual; KbReleaseWait; end end if manual % Query mouse: [xm ym]=GetMouse; walkspeed=(ym-500)/100; end t = GetSecs; telapsed = t - tstart; tstart = t; tdistance = telapsed * walkspeed; zposition = zposition + tdistance; alListenerfv(AL.POSITION, [0, 0, zposition]); fprintf('Z=%f\n', zposition); % Pause for 10 milliseconds in order to yield the cpu to other processes: WaitSecs(0.01); end % Stop playback of all sources: alSourceStopv(length(sources), sources); for i=1:nsources % Remove sound buffer: alSourcei(sources(i), AL.BUFFER, 0); end % Wait a bit: WaitSecs(0.1); % Delete buffer: alDeleteBuffers(nsources, buffers); % Wait a bit: WaitSecs(0.1); % Delete sources: alDeleteSources(nsources, sources); % Wait a bit: WaitSecs(0.1); % Shutdown OpenAL: CloseOpenAL; % Done. Bye. return;