Change computer.beep() to be non-blocking system-wide
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
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])
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...
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.
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).
That would be awesome! Thank you a million!
@ff66theone requesting progress report, what have you been able to do so far?
Also thank you, my gratefulness toward you is immeasurable.
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 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.
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)
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.
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
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.
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