Rob’s Tech & Tones

Where circuits meet sound

A musician who also happens to be an electronics engineer… or vice versa.

  • Joyo MOMIX CAB Reverse Engineering (Part 2)
    In other words, how I went from hardware limits to a custom firmware

    Hey! It’s Rob again, and this is part two of the Joyo MOMIX Cab reverse engineering.

    In the first part, I took a look at the hardware of the Joyo MOMIX Cab and quickly realized that disabling direct monitoring was not possible at the hardware level. Everything happens inside the DSP.

    This second part is where things finally worked.

    I managed to dump the original firmware. I tried to decompile it, without much luck. At that point, I changed approach. Using the official SDK, I wrote a new firmware from scratch and flashed it onto the device.

    The result is exactly what I was hoping for. Direct monitoring is gone, and the MOMIX Cab now behaves properly when used for guitar recording.

    Before getting into the details, a few updates since the last post.

    I didn’t get any response from either JL or JOYO, which I honestly expected. The good news is that the JL USB Updater finally arrived, and that allowed me to read and dump the flash memory of the device. Around the same time, the seller was kind enough to send me some documentation related to the JL AC6926A4, which helped clarify a few details about the platform.

    I also received the logic analyzer and the extra switch buttons, just in case they turn out to be useful later on.

    In the meantime, I spent some time tracing the PCB connections of the MOMIX Cab. Here’s what I’ve mapped so far:

    • PB0: “Aux” switch input, the unpopulated button on the board
    • PB1: Volume button minus
    • PB2: Volume button plus
    • PC4: Green LED
    • PC5: Red LED
    • MIC0 / PA0: audio input path

    I’ll probably try to draw a proper schematic as well, to make the project as complete as possible.

    While digging around, I also found out that the MOMIX Cab appears to be a variation of the Kewee Skyrecorder. There are also other devices that look essentially identical and are sold under different names, such as the Ueteto AI-8.

    In this post, I’ll go through what worked, what didn’t, and how I eventually got there.

    Let’s get to work.

    Step 1 – Using jl-uboot-tool

    The jl-uboot-tool is a utility developed by kagaimiq, who also wrote most of the available documentation on JL chips. The tool connects to the device once it has been put into UBOOT mode using the JL USB Updater.

    Once connected, a CLI appears, allowing the user to read, dump, or write the firmware. The device enters UBOOT mode simply by pressing the “update” button on the loader, which sends a special USB signal instructing the device to switch into UBOOT mode.

    For more details, check the in-depth guide by kagaimiq.

    Step 2 – Flash dump and Decompiling

    After I was able to connect to the device, I had to enter the correct command to dump the firmware. The command is “read”, but it requires a start address and an end address. To calculate this, I used the full flash memory size of the chip under test, the AC6926A4. The “4” in the chip code stands for 4 Mbit, which divided by 8 gives 512 KB. In hexadecimal, this is 0x80000:

    AC6926A4 = 4 Mbit = 512 KiB = 0x80000 bytes

    The complete command I used was:

    read 0x0000 0x80000 MomixCab.bin

    With this, the firmware was successfully dumped.

    The next step was to unpack and decrypt the firmware using the firmware tools from jl-misctools. From the extracted files, the following were obtained:

    • bt_cfg.bin
    • f_ascii_s.pix
    • sdk.app

    The file of our interest is sdk.app, which contains the main firmware code for the device.

    Note: If you encounter a problem with UTF encoding when running the scripts:

    You can fix it by editing the Python script and adding the following lines at the beginning:

    import sys
    import io
    sys.stdout = io.TextIOWrapper(sys.stdout.buffer, encoding='utf-8')

    After this change, the output should display correctly.

    Step 3 – Disassembly and Decompiling attempt

    The first thing that came to my mind was to try to disassemble and decompile the firmware, in the hope of finding something useful, such as a parameter that could be changed to disable the dry monitoring, maybe by patching the firmware directly.

    I tried several tools:

    • IDA
    • Ghidra
    • Binary Ninja
    • Hexview (which later turned out to be useful)

    That said, I am not a reverse engineer, so this quickly turned into a dead-end for me.

    Still, it was interesting to explore different ways of looking at binary files and to get a rough idea of how the firmware is structured.

    After that, I started looking for more information about JieLi chips in general and eventually stumbled upon the USMI forum. There, I found out that building a firmware from the official SDK and flashing it onto the device was actually more approachable than I initially thought.

    At that point, I started digging deeper into the SDK workflow and gradually realized that writing a new firmware for the device was not only feasible, but also the simplest and cleanest way forward.

    Step 4 – The JieLi SDK and the new MOMIX Firmware

    I started studying the JL SDK and after a lot of trial and error, I was able to write a new firmware for the device.

    I will explain all the steps of editing the SDK base project, separated by the section they belong to:

    Main Config File: sdk_cfg.h
    • Set USB_PC_EN = 1. This ensures that the device is in USB mode.
    • Set USB_SD0_MULT_EN = 0 and USB_SD1_MULT_EN = 0. This disables the SD card modules.
    • Force the clock to 192 MHz by setting SYS_Hz = 192000000L. This ensures the clock is at its maximum rate and prevents audio drops and corruption.
    • Disable Bluetooth by setting BLE_BREDR_MODE = 0. This ensures Bluetooth is always off.
    • Verify that unnecessary features are disabled (for example, ECHO_EN=0, REC_EN=0, FM_RADIO_EN=0). This reduces firmware size and ensures no other tasks run in parallel.
    Audio Parameters: DAC, LADC, Mic Gain & Attenuation
    • In audio_param.h, set the LADC buffer to 32 samples with DAC_SAMPLE_CON = 0. This was the only setting that worked:
      0 -> USB device works correctly
      1 -> audio crackling
      2 -> continuous pop (chip tries to start but cannot)
      3 -> device won’t turn on (probably asking for too much RAM)
    • In audio.h, increase the DAC buffer to 9216 bytes by modifying OUTPUT_BUF_SIZE to (576*2*2*4). This ensures output audio stability.
    • In ladc.c, add the function ladc_mic_gain_atten(u8 gain, u8 gx2, u8 neg12_en) after the existing ladc_mic_gain() function. This solves the problem of the input being too hot; -12 dB attenuation was the perfect solution.
    Board Parameters: Tasks, LEDs, Inits
    • In led.h, replace the entire #elif(LED_TYPE_SEL == LED_PXX) section. This initializes the on-board LEDs.
    • In board_init.c, uncomment the call to set_port_init(). This ensures the ports are initialized.
    • In board_init.c, after set_port_init(), add the calls LED_INIT_EN(); and B_LED_ON();. This ensures the power-on LED is on from the start.
    • In board.c, correct the task startup by replacing TASK_ID_BT with TASK_ID_PC in the task_switch() call. This ensures the task manager runs the correct task, i.e., the PC task.
    PC Device Configuration: USB User Descriptor
    • In dev_pc.c, replace the product string USER_RIPRODUCT_STR with "MomixCabMOD", ensuring its total length is set to 24 bytes. This is the name visible from the drop-down volume menu.
    • In dev_pc.c, replace the manufacturer string USER_IMANUFACTURE_STR with "JOYO Technology", setting the first byte to 0x22 (34 bytes total). This restores the original manufacturer name.
    • In dev_pc.c, inside the MIC section of app_usb_slave_init(), after ladc_ch_open(), add the line ladc_mic_gain_atten(0x02, 0, 1);. This ensures the mic attenuation is correctly set.

    I built the project, and the flashing started automatically.

    The device was recognized by the PC, and after some testing, it was fully functional! No dry-monitor in sight, just a plain USB audio interface with a mono input and stereo output.

    A problem appeared when connecting the device to a portable device: the error “the device is drawing too much current” showed up. After investigating, I found that the issue was caused by the USB_Descriptor class, in particular the bMaxPower field. Portable devices provide 100 mA of current, so adjustments were needed to make it compatible.

    Step 5 – Reverse Engineering the USB Protocol and Patching

    USB descriptors are data structures used by USB devices to describe their capabilities and requirements to the host. They include information such as device type, manufacturer, product name, supported configurations, endpoints, and power requirements.

    When a USB device is connected, the host requests these descriptors using standard USB requests, like GET_DESCRIPTOR and GET_CONFIGURATION. The data returned is a sequence of bytes, for example:

    09 02 00 00 ...

    Each byte or group of bytes has a specific meaning according to the USB specification. In this example, 09 indicates the descriptor length in bytes, 02 identifies the descriptor type (configuration descriptor), and the following bytes describe attributes such as total length, number of interfaces, and other parameters.

    By analyzing these descriptors, it is possible to see how the device presents itself, what interfaces it offers, and how much current it claims to draw. In our case, examining the USB descriptors was crucial to identify the excessive power draw reported by portable devices and to patch the firmware accordingly.

    By connecting the device to my PC and using Wireshark, I analyzed the GET DESCRIPTOR Response CONFIGURATION packet and found that the device had a 400 mA power limit, which is too high for our use case.

    The bMaxPower field multiplies 2 mA by its value, giving the maximum current parameter.

    Unfortunately, after some investigation, it was not possible to edit this parameter from the SDK, as it is probably hardcoded inside a library.

    It was time to open the sdk.app file and patch it manually. Using the original sdk.app as a reference, I confirmed that it was set at a 100 mA limit (hex 0x32 = decimal 50 × 2 mA).

    I then opened my compiled sdk.app and searched for the bytes that differed.

    By directly modifying the binary file with a hex editor, I located the sequence 80 C8 (hex 0xC8 = decimal 200 × 2 mA = 400 mA) within the configuration descriptor and replaced it with 80 32 to set the maximum current draw to 100 mA.

    After saving the file, I crossed my fingers, hoping there wouldn’t be any CRC checks during flashing.

    I then launched the download.bat file, and everything went smoothly

    I connected the Momix, launched a Wireshark capture, and voilà! The device was recognized and now set at 100 mA maximum power.

    For the final test, I connected it to my iPad and, hell yeah, I could record with GarageBand perfectly!

    Step 6 – Conclusion: Future Work and Added Functions

    I finally did what I wanted to do and what started as a personal challenge, pushing my abilities: remove the dry monitor function! During the process, I encountered some issues and tried to push the device as far as I could, keeping in mind that I only had access to an SDK and not a full programming environment. But I can say I’m happy with how everything turned out.

    The Momix is working well, but there’s still a little to-do list for this project:

    • The buttons are unused, so right now I have three (two stock + one added) buttons that can be mapped to functions.
      My ideas for the button functions:
      • Toggle dry monitor on/off (maybe someone will need it)
      • Toggle attenuation on/off
      • Input gain setting
    • The red LED is unused at the moment. It would be great to implement the input clipping indicator from the original device (the light turns red when the input is clipping).
    • Find a way to flash the firmware without having to buy the JL USB Updater, possibly using a solution based on the Arduino implementation by Christian Kramer
    • Create an app that can interface with the device to set parameters.

    For now, the main goal is done, so the project will take a pause. Any other experiments or improvements will happen little by little, whenever I find some free time.

    For now, that’s all, folks!

    I’ll see you later ✌️🏻

    Acknowledgements

    Many thanks to:

    Complete project available on my GitHub

  • Joyo MOMIX CAB Reverse Engineering (Part 1)

    Hi! My name’s Rob, I’m a musician and an EE with strong passion for music and anything audio related, and this is the first article on Rob’s Tech & Tones!

    It felt right to start with something that sits exactly at the intersection of electronics and music: reverse engineering an audio device.

    The device under test is a Joyo MOMIX Cab, a compact and affordable (~ 15 euros) audio interface, which can be used both with portable devices (it includes an USB-C to Lightning adaptor) and PC.

    It’s a great device but it has one major flaw: direct monitoring is always on and cannot be turned off. I can assure you that one thing that a guitarist won’t hear is the dry signal of the instrument alongside the audio coming from your VST/Amp Sim/etc.

    Since online I couldn’t find any procedure on how to turn off this function, in this article, I will attempt a reverse engineering of the device. The goal is not to reverse engineer a product to create my own version. I just want to understand how to turn off a specific feature to make it work better for guitar recording.

    The analysis is based on a teardown, PCB inspection, basic tracing, and simple measurements. Where information is incomplete or uncertain, I will clearly state assumptions and hypotheses rather than present them as facts.

    Step 1 – Teardown

    To start the disassembly, turn the Momix around so the clip on the back is accessible. On the clip, there is a small pin that you need to push out gently, taking care that the spring holding the clip in place does not fly away. Once the clip is removed, a screw will be exposed. Unscrew it, and then carefully lift off the plastic back cover to reveal the PCB. After that, you can gently pull out the PCB, and your device is ready for testing.

    Step 2 – PCB Analysis

    Using my beloved microscope, I was able to examine the PCB in detail. Below are pictures of the top and bottom of the PCB, created by combining several photos. This is why the colors may not appear perfectly consistent.

    DSP Side
    We’ll call this “DSP Side“…
    …and we’ll call this side “Amp Side

    The Momix is built around a simple but clever circuit,

    • Power stage: powered through a USB-C connector,
    • Input stage: a 6.35 mm TS jack feeds the signal, followed by filtering, probably around 20–25 kHz as suggested by the amp datasheet, and an amplifier used in a buffer configuration, the 721, also known as the RS721,
    • DSP stage: where all the magic happens ✨,
    • Output stage: includes filtering and a 3.5 mm TRS output jack.

    I had hoped for a simple parallel dry output circuit with an output mixer, but everything happens inside the DSP. This means that the modification to exclude direct monitoring cannot be done at the hardware level and would require editing the device’s firmware instead.

    Back to the analysis, this particular device is built around a JieLi chip, one of those famous chips often found in Bluetooth devices made in China, known for their iconic “ze blutut devis is ready for pair” sound.

    By tilting the PCB slightly, the IC code became visible. Searching for the code on Google did not yield any results. Luckily, there is a bit of documentation available, and thanks to the kagaimiq repo on GitHub, I was able to identify the chip as a JieLi AS6926A4. The code itself is informative: 26A identifies the chip model, and the 4 indicates the flash memory size in megabits. Finding a datasheet for this device online is not easy, since JieLi does not provide public documentation, but after some digging, I managed to locate one.

    What’s of interest for us is the chip layout and the chip definition table. By tracing the PCB, I was able to determine that the two volume buttons are connected to PB1 and PB2. On the DSP side of the board, there is also an empty slot for another switch, similar to the other two. This switch is connected to PB0 on the DSP. I soldered a button into the slot, but pressing it does nothing.

    One hypothesis is that it could be a button for putting the chip into programming mode. According to the kagaimiq documentation, the device should appear as a UBOOT device when in programming mode, but when checking in Windows, no UBOOT device appears. To this day, the function of this button remains unknown.

    PCB tracing

    I also tried using the JLUBootTool developed by the same author. The device is recognized, but the script gets stuck in the “try……” state and does not proceed to the UBOOT CLI. The chip probably needs to be put into a special state by an external device, such as the Force Bootloader Tool required for programming JL chips. I have ordered the tool, but it will take a few weeks to arrive.

    Next steps

    I have reached out to both JOYO and JL for information, the first regarding a possible future update for the device without the enabled monitoring function, and the second about possible commands that could be sent to the chip to disable the function. I will wait for their answers.

    I also found the SDK for the IC, so I need to study it to get a more complete understanding of the situation.

    In addition, I have ordered the Force Bootloader Tool and a logic analyzer, and now I just need to wait for them to arrive.

    For now, that’s all! Stay safe and keep on rollin’, rollin’, rollin’… 🧢

    Onto the next episode!

Design a site like this with WordPress.com
Get started