Sounds on Second Screen

My app uses a second screen for a beamer, which I put below my main screen (MacOS Display system preference).

I open different windows on either screens, either by window1.top = 1 or window2.top = 1+screen(0).height. Sometimes the played sound files come on the stereo speakers, sometimes on the built-in speakers of my MacBook. But I want the background music only to be there, and a Beep (e.g. wrong input) or selected sound should be on the Mac.

I have not figured out yet why some come there and others on the Mac. Is there description or an experience / explanation out there how to steer this?

You can use the MBS plugin to control any sound you play from a file. You can’t control where the system beep sound plays, though:

@Peter_Kronenberg - if this is just for you, you could try this app. I think it’ll do what you want:

Thanks guys for your help.

To give you some insight, here is the coding that first plays the sound on the beamer, and because all others in different methods didn’t, so I inserted a break before i play a second sound. That one does not play on the beamer anymore…?! Is it some ^how related with the active window?

’ 2nd screen is below 1st one
if ScreenCount > 1 then
WindowBackground.Top = Screen(0).Height + 1
WindowBackground.Left = 1
WindowBackground.Height = Screen(1).Height
WindowBackground.Width = Screen(1).Width
end

’ sounds
app.stopSounds
sound1.Play ’ on beamer
break
sound2.Play ’ comes on mac!?

I think the acitve window controls where the sound is played. Try making a “playbackWindow” and put that on the screen you want the sound from, from there play the sounds as property of the window and see how that works for you.

I have tried that, but I’m realising now that the initial sound was never from the beamer, it was always from the MacBook, it sounded just that spacious… Sorry, embarrassing.

So: how can I distribute the sound via the System Preference to different output devices? That might be the solution.

Emile suggested via declare to the Apple sound manager… how is that be done?

You can try via termal to play sound. Use the shell class, or MBS plugins.

The easiest way, if you have the MBS plugin, is to use the AUPlayerMBS class. You can enumerate devices and play sounds to one you choose (without ever altering the computer’s default settings).

Thanks Arnaud, I am looking into that.

Indeed, I could load the table of all the devices, however when I assign a key to the CurrentDevice it stays always 0.

And I’m not sure how to play a sound, since I keep mine in the app, not as an external file, so auplayer.loadfile / play is not possible.

Which key value are you adding?

FWIW, here’s a code which may get you started (I simplified it from one of my projects, so I hope it’s still working like this, but it should give you an idea).

Add a property to the window (Player as AUPlayerMBS).

Then:

Var outSize as integer
Var outWriteable as boolean
Var idev,odev as integer
Var c As new CoreAudioMBS

c.AudioHardwareGetPropertyInfo "dev#",outSize,outWriteable
Var ids as MemoryBlock=c.AudioHardwareGetPropertyMemory("dev#")

Var DevicesCount As Integer=outSize/4

//Get the default input and output device IDs
Var m As MemoryBlock=c.AudioHardwareGetPropertyMemory(c.kAudioHardwarePropertyDefaultInputDevice)
idev=m.Long(0)

m=c.AudioHardwareGetPropertyMemory(c.kAudioHardwarePropertyDefaultOutputDevice)
odev=m.Long(0)

//Get the device ID for each device
ids=c.AudioHardwareGetPropertyMemory("dev#")

for i as Integer=0 to DevicesCount-1
  var id As Integer=ids.Long(i*4) // 4 bytes per integer
  Var IsInput As Boolean=c.AudioDeviceGetPropertyString(id,0,true,c.kAudioDevicePropertyStreamFormat)<>""
  Var IsOutput As Boolean=c.AudioDeviceGetPropertyString(id,0,false,c.kAudioDevicePropertyStreamFormat)<>""
  Var DeviceName As String=c.AudioDeviceGetPropertyString(id,0,True,c.kAudioDevicePropertyDeviceName).DefineEncoding(Encodings.UTF8)
  
  if DeviceName="TheDeviceName" then
    if Player.LoadFileMT(AudioFile) then
      Var od As String=snd.OutputDevice
      
      Var List() As CAudioDevice=GetMacAudioDevices(False)
      Var DeviceID As Integer=if(od<>"" and od<>"Par défaut",GetDeviceIDIndexForDevice(od,List,False,False),if(app.Prefs.DefaultGameDevice<>nil,app.Prefs.DefaultGameDevice.DevID,GetDefaultOutputDevice))
      
      Player.CurrentDeviceID=DeviceID
      
      Player.OutputVolume=1
      Player.InputEnabled(0)=True
      Player.InputEnabled(1)=True
      Player.InputVolume(0)=1
      Player.InputVolume(1)=1
      exit
    end if
  end if
next

I guess it complicates things. Xojo doesn’t provide a way to access an existing sound object to convert it to a file or RAW data, so you can’t save it to a temporary file or load the sound from RAM, as far as I know.
I’m wondering whether your sounds appear in the Resources folder of the built app (not yet tested).

I found my sound indeed in the Resource folder.

Your code seems to me way to complicated… Anyway, I gat strange Lasters codes from my code, any ideas why?

// handle sounds

var f as folderitem
var b as boolean

’ stop actual sound
auplayer.Pause ’ stop not existing…

’ get new one
select case sd
case ambientintrosynthsound
f = SpecialFolder.Resources.Child(“ambientintrosynthsound.mp3”)
case attackdrums
f = SpecialFolder.Resources.Child(“attackdrums.mp3”)
else
errorMsg "Unknown sound file…! "
return
end select

’ play that sound
auplayer.CurrentDeviceID = auid ’ output id, eg of beamer
if auplayer.Lasterror <> 0 then
msgbox "auid "+str(auplayer.Lasterror) ’ getting -50
end
b = auplayer.LoadFile(f,1,1)
if b = false then
msgbox "load "+str(auplayer.Lasterror) ’ getting 2003334207
else
auplayer.Play
if auplayer.Lasterror <> 0 then beep
sdold = sd
end

Well, complete codes give more hints. I don’t know how you’re finding your device nor what is important to you.

Could you define “lasters”, please? I can’t translate it.

Just asking the obvious: your sounds have really 1 channel, right?
Possibly, you still have to specify 2 channels for the output device. Have you tried (f,1,2)?

Sorry Arnaud, that was a typo: ‘I got strange errorcodes…’ I indicated them in the comment after the line.
Regarding output channel I was just experimenting, guess the default of 2,2 is okay.

No problem.
When you get an unknown Mac error code, you can usually look them up at http://osstatus.com.
In your case, it’s a kind of “unspecified” error (yet listed), but it mentions the source of the issue being the file, hence why I asked if your files were really 1 channel wide.

Experimenting shouldn’t be needed, these parameters are logical :wink:
The first numeric parameter should match the number of channels of your input file, while the second one should reflect the device’s channels count.
Glad you sorted it out.

Success. I managed to play now the sound on different devices!
The error -50 was due to a typo in the sound file name…
And the other error because I did stuff before loading the sound file…

One small problem still: if I want to play a second sound, and even if i use

if auplayer.playing then auplayer.reset

I get when doing the next auplayer.Loadfile(f) an Unsupported Operation exception (the class can load only one file). How do I load a new or ‘unload’ the previous sound file, or is auplayer = new AUplayerMBS strictly every time necessary?