Loopy Pro: Create music, your way.

What is Loopy Pro?Loopy Pro is a powerful, flexible, and intuitive live looper, sampler, clip launcher and DAW for iPhone and iPad. At its core, it allows you to record and layer sounds in real-time to create complex musical arrangements. But it doesn’t stop there—Loopy Pro offers advanced tools to customize your workflow, build dynamic performance setups, and create a seamless connection between instruments, effects, and external gear.

Use it for live looping, sequencing, arranging, mixing, and much more. Whether you're a live performer, a producer, or just experimenting with sound, Loopy Pro helps you take control of your creative process.

Download on the App Store

Loopy Pro is your all-in-one musical toolkit. Try it for free today.

iOS Safari WebAudio -- severe distortion on output

edited January 2021 in Other

I'm trying to generate a PWM signal to control external electronics using the headphone jack.

This works flawlessly from a normal Linux computer, and also from a native iOS app.

However, the exact same code (well, in JavaScript, but you know what I mean!) generates an extremely distorted output signal that is completely unusable for the task.

Very odd!

"Good" signal: (Linux, native iOS app):

"Bad" signal: (exact same, dead simple code, WebAudio Safari)

Does anyone know what's going on here or how to prevent this? Either Apple is not even capable anymore of passing a ScriptProcessor node's output 1:1 to the destination, or they're applying some kind of "nice" EQ/processing/compression or whatever. Hopefully with a way to turn it off!

(I thought about Measurement Mode, but that's apparently not controllable from WebAudio -- fair enough!)

EDIT: To me it almost looks as if some kind of high-pass filtering is going on (but I swear I don't have a highpass in my code :D )

UPDATE: Here's a spectral analysis of the "correct" output:

Here's Safari's:

Very odd... the spectrum almost looks, errr, "smoothed out", as if it had a lower frequency resolution. Not sure what kind of filter would create that, it's definitely not a high or low pass though...

UPDATE: Another interesting thing is that on Safari, the output is forced mono. I've modified the code to invert one stereo channel, and the result is complete silence on Safari.

Yeah WebAudio on iOS is ready for production! :D

ANOTHER UPDATE: I've managed to get rid of the problem, and it's extremely interesting: It only occurs when there's a parallel navigator.mediaDevices.getUserMedia stream running, i.e. if I'm streaming microphone input at the same time. As soon as I get rid of that, the output is undistorted.

So it seems like iOS is switching into some kind of "phone mode" because it assumes that if a website uses input and output at the same time, it must be some kind of VoIP app. Why it then however strongly compresses the audio output without me requesting it, no idea...

OK, well. I hope it has been an interesting read so far :D

Comments

  • @SevenSystems As soon as I saw your waveform, I thought "that's AC-coupled". Don't think it's anything magical, just a telephone-style high-pass filter, as you suggest. With a break frequency at 300 Hz (typical), it would work like a differentiator for DC levels, and that's what you see; each edge turned into a pulse. It's not any form of exotic compression or equalization, just a simple filter.

  • The user and all related content has been deleted.
  • @uncledave said:
    @SevenSystems As soon as I saw your waveform, I thought "that's AC-coupled". Don't think it's anything magical, just a telephone-style high-pass filter, as you suggest. With a break frequency at 300 Hz (typical), it would work like a differentiator for DC levels, and that's what you see; each edge turned into a pulse. It's not any form of exotic compression or equalization, just a simple filter.

    Actually, it does look to me like it's some form of compression. My reasoning is that 1) there are no parts of the spectrum missing (apart from the very top end, and especially no low end), and 2) the spectrum looks "complete" and "original" overall, but has a lower frequency resolution (it looks more "smooth" in the X axis), which tells me that this must be some form of FFT-based compression going on.

    Still sucks :D

    @tja said:
    I always like reading such content, @SevenSystems
    Did you report this back to Apple?

    As developer, you may get their ear... we regular users can only give feedback without any sort of reply.

    I probably should, yeah, although I haven't been very successful with getting useful feedback on my reports in the past (all of which were relevant and valid). Just as one example, I've reported the various iOS 13 statusbar-related bugs at least one year ago, and they still haven't been fixed. And that's highly-visible mainstream bugs!

  • @SevenSystems said:

    @uncledave said:
    @SevenSystems As soon as I saw your waveform, I thought "that's AC-coupled". Don't think it's anything magical, just a telephone-style high-pass filter, as you suggest. With a break frequency at 300 Hz (typical), it would work like a differentiator for DC levels, and that's what you see; each edge turned into a pulse. It's not any form of exotic compression or equalization, just a simple filter.

    Actually, it does look to me like it's some form of compression. My reasoning is that 1) there are no parts of the spectrum missing (apart from the very top end, and especially no low end), and 2) the spectrum looks "complete" and "original" overall, but has a lower frequency resolution (it looks more "smooth" in the X axis), which tells me that this must be some form of FFT-based compression going on.

    Still sucks :D

    @tja said:
    I always like reading such content, @SevenSystems
    Did you report this back to Apple?

    As developer, you may get their ear... we regular users can only give feedback without any sort of reply.

    I probably should, yeah, although I haven't been very successful with getting useful feedback on my reports in the past (all of which were relevant and valid). Just as one example, I've reported the various iOS 13 statusbar-related bugs at least one year ago, and they still haven't been fixed. And that's highly-visible mainstream bugs!

    Definitely agree that it sucks.

    Spectrum analysis may not be the best way to analyze a non-repeating time-domain waveform. I feel that you're overthinking the problem.

  • edited January 2021

    @uncledave said:

    @SevenSystems said:

    @uncledave said:
    @SevenSystems As soon as I saw your waveform, I thought "that's AC-coupled". Don't think it's anything magical, just a telephone-style high-pass filter, as you suggest. With a break frequency at 300 Hz (typical), it would work like a differentiator for DC levels, and that's what you see; each edge turned into a pulse. It's not any form of exotic compression or equalization, just a simple filter.

    Actually, it does look to me like it's some form of compression. My reasoning is that 1) there are no parts of the spectrum missing (apart from the very top end, and especially no low end), and 2) the spectrum looks "complete" and "original" overall, but has a lower frequency resolution (it looks more "smooth" in the X axis), which tells me that this must be some form of FFT-based compression going on.

    Still sucks :D

    @tja said:
    I always like reading such content, @SevenSystems
    Did you report this back to Apple?

    As developer, you may get their ear... we regular users can only give feedback without any sort of reply.

    I probably should, yeah, although I haven't been very successful with getting useful feedback on my reports in the past (all of which were relevant and valid). Just as one example, I've reported the various iOS 13 statusbar-related bugs at least one year ago, and they still haven't been fixed. And that's highly-visible mainstream bugs!

    Definitely agree that it sucks.

    Spectrum analysis may not be the best way to analyze a non-repeating time-domain waveform. I feel that you're overthinking the problem.

    I tend to :) Anyway, seems like there is no obvious solution to this problem and I need to improvise.

    If anyone is interested in the background: the goal is to control a standard RC servo (like they're used in model cars, etc.) using the iPhone headphone jack. The output level is not quite high enough to trigger some servos (including mine), so I had to add a coupling capacitor and a voltage divider to lift the signal far enough so that the positive pulse is above the servo's input threshold.

    This part works if I don't use mediaDevices.getUserMedia. The latter was intended to receive an ultrasound control signal that provides the desired position of the servo (I chose ultrasound because Bluetooth's range is too short). The ultrasound "protocol" is pretty simple -- two separate tones that have to have the correct frequency ratio and a certain minimum S/N ratio, and then the average frequency of the two is proportional to the desired servo position.

    The ultrasound control also works as intended, however as I said I can't combine the two because then the output is distorted.

    So I'll try reverting to using UDP over WiFi as a hopefully more or less reliable compromise. I've already searched the internet though and it seems like UDP, like everything in iOS, is also royally fucked up. But let's see :)

  • The user and all related content has been deleted.
  • edited January 2021

    @tja said:
    Totally impressed by what you are doing, @SevenSystems
    :o :o :o

    The only impressive thing about it is probably how dodgy it is :D but thanks!

    (my only equipment is a $10 Lidl multimeter and another $10 Chinese soldering iron so my errr, build quality is limited!)

    (all parts are extracted from scrap electronics around the house so the coupling capacitor is ridiculously huge and the voltage divider is a cheapass volume pot from a $10 Tesco radio which I need to adjust to about 1/100th degree precision for the whole thing to work :D )

  • wimwim
    edited January 2021

    @SevenSystems said:
    If anyone is interested in the background: the goal is to control a standard RC servo (like they're used in model cars, etc.) using the iPhone headphone jack. The output level is not quite high enough to trigger some servos (including mine), so I had to add a coupling capacitor and a voltage divider to lift the signal far enough so that the positive pulse is above the servo's input threshold.

    This part works if I don't use mediaDevices.getUserMedia. The latter was intended to receive an ultrasound control signal that provides the desired position of the servo (I chose ultrasound because Bluetooth's range is too short). The ultrasound "protocol" is pretty simple -- two separate tones that have to have the correct frequency ratio and a certain minimum S/N ratio, and then the average frequency of the two is proportional to the desired servo position.

    The ultrasound control also works as intended, however as I said I can't combine the two because then the output is distorted.

    So I'll try reverting to using UDP over WiFi as a hopefully more or less reliable compromise. I've already searched the internet though and it seems like UDP, like everything in iOS, is also royally fucked up. But let's see :)

    It's easy enough to control a Wifi or BLE capable Arduino type device, or a Raspberry Pi Zero W from an iPhone. You don't need to jump through any hoops to get servos to work with those guys. A Pi Zero W costs $14 US.

    (edit ... oh, BLE range is too short. Oh well, wifi then. https://gpiozero.readthedocs.io/en/stable/remote_gpio.html)

  • The user and all related content has been deleted.
  • @wim said:

    @SevenSystems said:
    If anyone is interested in the background: the goal is to control a standard RC servo (like they're used in model cars, etc.) using the iPhone headphone jack. The output level is not quite high enough to trigger some servos (including mine), so I had to add a coupling capacitor and a voltage divider to lift the signal far enough so that the positive pulse is above the servo's input threshold.

    This part works if I don't use mediaDevices.getUserMedia. The latter was intended to receive an ultrasound control signal that provides the desired position of the servo (I chose ultrasound because Bluetooth's range is too short). The ultrasound "protocol" is pretty simple -- two separate tones that have to have the correct frequency ratio and a certain minimum S/N ratio, and then the average frequency of the two is proportional to the desired servo position.

    The ultrasound control also works as intended, however as I said I can't combine the two because then the output is distorted.

    So I'll try reverting to using UDP over WiFi as a hopefully more or less reliable compromise. I've already searched the internet though and it seems like UDP, like everything in iOS, is also royally fucked up. But let's see :)

    It's easy enough to control a Wifi or BLE capable Arduino type device, or a Raspberry Pi Zero W from an iPhone. You don't need to jump through any hoops to get servos to work with those guys. A Pi Zero W costs $14 US.

    (edit ... oh, BLE range is too short. Oh well, wifi then. https://gpiozero.readthedocs.io/en/stable/remote_gpio.html)

    Yes, I've heard about Arduino... but then, I'd need to learn a whole new ecosystem to implement a one-off thing that I'll probably never need again -- while I already know "standard" web (and general UNIX / C) programming. But you're right of course, your approach is by far more robust :D (but mine is far cheaper and, let's be honest, cooler! :D )

    @Max23 said:
    Web audio is a bag of hurt.
    Chrome supports different stuff than Safari ...

    I know... I still check the WebKit feature status page daily to see when they finally have the modern WebAudio implementation that Chrome has had for years. There's hope though, as buried in Settings -> Safari -> Advanced -> Blahblah, there's now a "Modern WebAudio API" switch!

  • wimwim
    edited January 2021

    @SevenSystems said:
    Yes, I've heard about Arduino... but then, I'd need to learn a whole new ecosystem to implement a one-off thing that I'll probably never need again -- while I already know "standard" web (and general UNIX / C) programming. But you're right of course, your approach is by far more robust :D (but mine is far cheaper and, let's be honest, cooler! :D )

    What kind of attitude is that?? My latest one-off thing that I'll probably never use again caused me to dive into two new environments (Pi and Arduino), a new language (C/Arduino), at least $100 worth of breadboards, LEDs, encoders, etc. And a 3d printer! Where in the world does practicality come into play for a geek obsession??

    I'm lookin' at the end result sitting unused on the table in front of me. Still ... it makes me feel happy (and more than a little guilty and foolish).

  • @wim said:

    @SevenSystems said:
    Yes, I've heard about Arduino... but then, I'd need to learn a whole new ecosystem to implement a one-off thing that I'll probably never need again -- while I already know "standard" web (and general UNIX / C) programming. But you're right of course, your approach is by far more robust :D (but mine is far cheaper and, let's be honest, cooler! :D )

    What kind of attitude is that?? My latest one-off thing that I'll probably never use again caused me to dive into two new environments (Pi and Arduino), a new language (C/Arduino), at least $100 worth of breadboards, LEDs, encoders, etc. And a 3d printer! Where in the world does practicality come into play for a geek obsession??

    I'm lookin' at the end result sitting unused on the table in front of me. Still ... it makes me feel happy (and more than a little guilty and foolish).

    Haha... yes, well, totally valid points. I had actually considered diving into 3d printing as well, as I would definitely benefit from a few custom plastic parts for this servo project. I'll try doing it all with (good) duct tape and a few cable ties for now, hope that'll work ;) but I did actually already model the part I'd need in Blender and played around with it in Cura! Unfortunately, I'd need a lot of overhang so the only viable option would probably be a printer with two feeds so I could use one for that water-soluble remove-later overhang-killer material (you'll know what I mean if you're into this already...)

    I've briefly used a generic WiFi relay module which was based on Arduino, but came pre-programmed as a WiFi AP and with 2 relays and a simple TCP/IP commandset. However, it would constantly reset itself as soon as the actual motor started or stopped, which I assume was due to EMI. That made me immediately hate it and well, if I use an iPhone with my WebAudio hack above, it's at least already EMI-approved and won't crash when I turn the servo :D

  • wimwim
    edited January 2021

    @SevenSystems said:
    Haha... yes, well, totally valid points. I had actually considered diving into 3d printing as well, as I would definitely benefit from a few custom plastic parts for this servo project. I'll try doing it all with (good) duct tape and a few cable ties for now, hope that'll work ;) but I did actually already model the part I'd need in Blender and played around with it in Cura! Unfortunately, I'd need a lot of overhang so the only viable option would probably be a printer with two feeds so I could use one for that water-soluble remove-later overhang-killer material (you'll know what I mean if you're into this already...)

    I'm not so fearful of overhang now. Removing supports is a lot easier than I thought it would be in most cases. But ... I feel like the 3d printer was a silly purchase. I'll never get the use out of it that would justify the expense, unless I include the learning / entertainment value.

  • @wim said:

    @SevenSystems said:
    Haha... yes, well, totally valid points. I had actually considered diving into 3d printing as well, as I would definitely benefit from a few custom plastic parts for this servo project. I'll try doing it all with (good) duct tape and a few cable ties for now, hope that'll work ;) but I did actually already model the part I'd need in Blender and played around with it in Cura! Unfortunately, I'd need a lot of overhang so the only viable option would probably be a printer with two feeds so I could use one for that water-soluble remove-later overhang-killer material (you'll know what I mean if you're into this already...)

    I'm not so fearful of overhang now. Removing supports is a lot easier than I thought it would be in most cases. But ... I feel like the 3d printer was a silly purchase. I'll never get the use out of it that would justify the expense, unless I include the learning / entertainment value.

    Yeah, that'd be my main fear. Unless I'd actually need it for commercial work, rapid prototyping etc., it's probably going to be similar to a hobby drone. Lots of fun........................................... for 2 days!

Sign In or Register to comment.