OpenComputers icon indicating copy to clipboard operation
OpenComputers copied to clipboard

Change computer.beep() to be non-blocking system-wide

Open ReallySecureShell opened this issue 5 months ago • 13 comments

OpenComputers Mod Version: 1.8.9a for Minecraft 1.12.2 OpenOS version of test system: OpenOS 1.8.8 LUA Version: Lua 5.3

As discussed in issue #1112 computer.beep() is a blocking call. On OpenComputers version 1.8.9a computer.beep() will block all execution on the computer until the call completes, including if computer.beep() was called from a detached thread.

I would appreciate it if instead of computer.beep() blocking execution system-wide, calling it only blocks within the thread it was executed from. The consequence of this change would enable users to have multiple instances of computer.beep() running concurrently using threads, which I believe would be an improvement to the current system.

I understand that the Computronics mod by Vexatos adds a beepcard that is non-blocking. However, the behavior of computer.beep() in the mainline mod should still be changed so that it at least does not block execution system-wide.

The following example code shows computer.beep() blocking execution of the main program thread while it runs within the detached thread:

local computer = require("computer")
local event    = require("event")
local thread   = require("thread")

local play_audio_tone = thread.create(function(tone_id)
  -- tone 1
  -- 340Hz 500ms on, 500ms off Intermittent
  local function tone1()
    local t = 0

    for i = 1, 4 do
      if (i % 2) == 1 then
        computer.beep(340, 0.50)
      else
        t = computer.uptime()
        repeat os.sleep(0) until( ( computer.uptime() - t ) >= 0.50 )
      end
    end
    computer.pushSignal("tone_complete", 1)
  end

  local PLAY_TONES = {
    [1] = function() tone1() end
  }

  -- crude system for picking which audio tone to play for testing using args passed from shell
  if type(tone_id) == "number" and tone_id > 0 and tone_id <= 8 then
    --event.timer(1, PLAY_TONES[tone_id)
    PLAY_TONES[tone_id]()
  else
    print("Invalid argument")
  end

  while true do
    local event, param1 = event.pullMultiple("interrupted", "tone_complete")

    if event == "interrupted" then
      print("interrupted")
      break
    elseif event == "tone_complete" then
      PLAY_TONES[param1]()
    end
  end
end, 1):detach()

local iter = 0

while true do
  os.sleep(1)
  print(iter)
  iter = iter + 1
end

ReallySecureShell avatar Aug 07 '25 03:08 ReallySecureShell

Also I think that space characters ( ) should be added to computer.beep(). The presence of a space character when using computer.beep() in Morse code mode would add X milliseconds (ms) of silence (could be like 50ms or however long a - character plays for).

Lastly, it would be great to choose the tone frequency when using computer.beep() in Morse code mode using an optional parameter.

Example: computer.beep("...---...", 440) Syntax: computer.beep(string, [frequency])

ReallySecureShell avatar Aug 07 '25 04:08 ReallySecureShell

or maybe GRUB's way to represent beeps could be implemented, since it has everything. You can define precisely the sequence since you tell the tempo, legnth of the note to play and its frequency. Using this notation also allows for making delays, making music files finally a reality...

ff66theone avatar Aug 07 '25 10:08 ff66theone

or maybe GRUB's way to represent beeps could be implemented, since it has everything. You can define precisely the sequence since you tell the tempo, length of the note to play and its frequency. Using this notation also allows for making delays, making music files finally a reality...

That would be cool too. And honestly that would be the best outcome.

I guess my biggest problem with how computer.beep() is implemented currently is that it has limited usability because of the way it currently functions. We do have Computronics (which from what I've read) looks like you can make music in it, albeit not exactly like grub.

I think realistically the easiest thing to do is to implement the changes into the Morse code mode as I suggested above. Only because its already there, the Morse code mode is already non-blocking, and I figure it should be more straight forward then making calls to computer.beep(freq, duration) non-blocking.

ReallySecureShell avatar Aug 07 '25 18:08 ReallySecureShell

Old games used the buzzer extensively and exploited timings and physics to transform a square wave into more sophisticated music, but unfortunately we do not have realistic buzzer simulation :) I don't think it would be an issue to add tempo and pitch to the morse code as well I could try to look into the code in the next days, see what I can do for you What I'll do is make the space the same length as it is officially, aka 4 dots long (separation between 2 letters that is).

ff66theone avatar Aug 08 '25 00:08 ff66theone

That would be awesome! Thank you a million!

ReallySecureShell avatar Aug 08 '25 01:08 ReallySecureShell

@ff66theone requesting progress report, what have you been able to do so far?

Also thank you, my gratefulness toward you is immeasurable.

ReallySecureShell avatar Aug 18 '25 00:08 ReallySecureShell

Because I was working on other mods in parallel, all I did for now it find where the pattern is decoded, however it looks like it would be hard to add the GRUB format to the function. Adding the space thing would be easy enough, and the only reason I think computer.beep is blocking is because it's implemented in Machine.scala. However, all this function does is send a sound packet to the client, and then the client decodes the patterns or plays the tune. Adding features to computer.beep would be easy enough, but resolving that issue may be harder than you think.

The fact computer.beep plays a sound is surely the reason why it's blocking system-wide, I think it's because the Lua interpreter makes an external call like this. If anyone has an better idea of why this is the case and/or has a solution, we are open.

ff66theone avatar Aug 18 '25 11:08 ff66theone

@ff66theone Understood, thank you. I would say the best option right now would be to add the space (pauses) into the Morse code mode as you said, and if possible add an optional parameter when using Morse code mode to allow the user to choose a frequency between 20 and 2000.

ReallySecureShell avatar Aug 18 '25 14:08 ReallySecureShell

Frequency seems to be possible but would require a change in the packet format for audio beeps, potentially rendering incompatible with older clients (but idk really) Also I've seen that we could use the / instead for a 4-long pause, and a space for a 7 long pause (just went on Wikipedia not so long ago)

ff66theone avatar Aug 19 '25 18:08 ff66theone

Got it, at worst case if it does make audio beeps incompatible, we can just document the new way to do it. Hopefully it won't matter since it would be on the backend but we'll see. Also I agree with using '/' instead for a 4-long pause if that's what the standard way to do it is.

ReallySecureShell avatar Aug 24 '25 20:08 ReallySecureShell

I swear we needed this like atleast 7 years ago we could actually have notification beeps without halting the system or having soundtrack on games without needing to use the sound card from computeronics

TheOOF10 avatar Nov 01 '25 19:11 TheOOF10

I swear we needed this like atleast 7 years ago we could actually have notification beeps without halting the system or having soundtrack on games without needing to use the sound card from computeronics

One of the reasons it has been made blocking is to avoid packet spam from computers. With the OpenFM mod I had made a similar thing since I was hosting my own music files and the OC program would make the radio change musics. However, a bug made it spam a lot of HTTP requests to my computer nearly DDoSing it, so yeah, packet spam is bad.

ff66theone avatar Nov 02 '25 17:11 ff66theone

One of the reasons it has been made blocking is to avoid packet spam from computers. With the OpenFM mod I had made a similar thing since I was hosting my own music files and the OC program would make the radio change musics. However, a bug made it spam a lot of HTTP requests to my computer nearly DDoSing it, so yeah, packet spam is bad.

We could just make it so that there is a minimum duration of each beep (for example either 10ms or 1 tick) and that if another beep call is made while the computer is beeping it is sent to a queue stored in client

TheOOF10 avatar Nov 02 '25 18:11 TheOOF10