SoLoud Audio Engine

repository·master·Indexed 24 days ago

https://github.com/jarikomppa/soloud

A portable, lightweight C/C++ audio engine designed for game development. Distributed under the Zlib/LibPng license, it provides tools for audio playback, including specialized components like ChipPlayer for AY chip emulation, SNDBUFFER for audio mixing, and a Klatt speech synthesizer.

Tokens
4.3K
Snippets
9
Records
31
Agent score
80%

What's inside SoLoud

  1. Overview of SoLoud audio engine

    master
    SoLoud is a free, portable C/C++ audio engine designed specifically for games. It is licensed under Zlib/LibPng, making it suitable for various project types. It is designed to be easy to use and highly portable across different platforms.
  2. Build GLEW from scratch with custom extension data

    master

    To build GLEW from scratch (for example, to update extension data from the web or add your own extension information), you must have a Unix environment with wget, perl, and GNU make installed.

    Regenerate the extension data from the top-level source directory using the make extensions command.

    make extensions
  3. Generate glue code for non-C environments using codegen

    master
    The codegen tool parses SoLoud C++ headers to produce a soloud_codegen.py file. This generated Python script can then be used to create various 'glue' code implementations, allowing SoLoud to be used in environments other than C/C++.
  4. Install GLEW from a tarball on Unix

    master

    If you have downloaded the GLEW tarball from the official website, you can install it on a Unix-based system by running the following commands in sequence:

    1. Build the project using make.
    2. Install the library using sudo -s followed by make install.
    3. Clean up the build files using make clean.
    make
    sudo -s
    make install
    make clean
  5. Use SNDBUFFER for AY sound emulation and rendering

    master

    The SNDBUFFER class acts as a shared audio buffer for multiple sound sources (like AY chips or beepers) to mix into. It manages sample storage, tracks how many samples are ready for playback, and handles buffer zeroing after samples are read to ensure continuous mixing.

    Key Workflow

    1. Initialize: Create an SNDBUFFER with a specific size.
    2. Emulation Loop: In your emulation loop, call count_start() on the buffer, then call count(source) for each sound source (e.g., SNDCHIP or SNDRENDER) to let them write to the buffer.
    3. Calculate Ready Samples: Call count_end() to get the total number of samples ready for playback.
    4. Retrieve Buffers: Use get_buffers() to get the memory positions and sizes of the contiguous segments ready to be played.
    5. Playback and Reset: Play the retrieved buffers and call samples_read(count) to notify the buffer that the samples have been consumed, allowing it to zero out that memory for the next mixing cycle.
    SNDBUFFER buf(4096);
    SNDCHIP ay1(buf), ay2(buf);
    SNDRENDER beeper(buf);
    
    // Inside emulation loop
    for (;;) {
        // ... emulation logic ...
    
        buf.count_start();
        buf.count(ay1);
        buf.count(ay2);
        buf.count(beeper);
        unsigned n_samples = buf.count_end();
    
        bufptr_t pos1, pos2;
        unsigned size1, size2;
        buf.get_buffers(pos1, size1, pos2, size2, n_samples);
    
        // Play the segments
        wav_play(buf.buffer + pos1, size1);
        wav_play(buf.buffer + pos2, size2);
    
        // Notify buffer to zero out read samples
        buf.samples_read(n_samples);
    }
  6. Configure SNDRENDER timing parameters

    master

    Use set_timings to define the relationship between the emulated system's clock and the target audio sample rate. This is critical for correct resampling.

    Parameters:

    • sys_clock_rate: The frequency of the emulated system clock (e.g., SNDR_DEFAULT_SYSTICK_RATE for a ZX-Spectrum).
    • sample_rate: The target audio sample rate (e.g., SNDR_DEFAULT_SAMPLE_RATE).
  7. Configure ChipPlayer timings and volumes

    master

    To ensure the AY chip emulation runs at the correct speed and volume levels, use the following configuration methods on a ChipPlayer instance:

    • set_timings(unsigned system_clock_rate, unsigned chip_clock_rate, unsigned sample_rate): Sets the clock rates for the system, the chip, and the output sample rate.
    • set_volumes(SNDCHIP::CHIP_TYPE t, unsigned global_vol, const SNDCHIP_VOLTAB *vt, const SNDCHIP_PANTAB *pt): Configures the volume tables and global volume for a specific chip type.
  8. Interact with SID registers via read and write

    master

    For low-level emulation or direct register control, use the read and write methods to interact with the SID chip's memory map.

    • unsigned char read(unsigned int adr): Reads a byte from the specified address.
    • void write(unsigned int adr, unsigned char byte): Writes a byte to the specified address.
  9. Use the SNDRENDER class for sound resampling

    master

    The SNDRENDER class is used to convert DAC (Digital-to-Analog Converter) inputs into a PCM buffer, specifically designed for sound resampling in emulation contexts (like the Unreal Speccy project). It manages the relationship between a system clock (e.g., Z80 clock) and the audio sample rate.

    To use SNDRENDER, you must provide an SNDBUFFER during construction. You can then control the emulation process using frame-based updates or direct rendering.

  10. Emulate DAC updates with SNDRENDER

    master

    When emulating a system that writes to a DAC, use the following sequence to fill the SNDBUFFER:

    1. start_frame(): Call this at the beginning of an emulation frame. It resets the internal system tick counter to 0.
    2. update(unsigned sys_tick, unsigned l, unsigned r): Call this whenever the emulated system writes a new value to the Left (l) or Right (r) DAC channels at a specific system clock sys_tick.
    3. end_frame(unsigned endframe_sys_tick): Call this at the end of the frame. It ensures that the last DAC value is emulated (held constant) until the specified endframe_sys_tick.
  11. Render synthesized audio to a buffer with TED

    master

    To generate audio data from the TED synthesis engine, use renderSound. This method writes the synthesized samples into a provided buffer.

    • renderSound(unsigned int nrsamples, short *buffer): Renders nrsamples into the provided short buffer.
    • storeToBuffer(short *buffer, unsigned int count): Stores the current state/sound to a buffer.