News:

NetSurf: the first new browser for OPENSTEP in decades!

Main Menu

What Needs to be done for a NeXT Emulator

Started by andreas_g, Sep 08, 2025, 04:47 PM

Previous topic - Next topic

mikeboss

IMHO it's always better to capture the unmolested data. filters can easily be applied later if desired.

andreas_g

This makes sense for me too. Volume can be adjusted easily during playback to the recorded data itself. Filters can also be applied and the current low-pass filter does not match real hardware anyway.

But one issue remains: The Soundbox accepts 44,1 and 22,05 kHz audio streams. Depending on setup it performs upsampling of 22,05 kHz data using sample repetition or zero-filling. Probably this step should be taken before saving the sound?

Rhetorica

Yes, just export 44.1 kHz. If someone truly needs to recover the 22050 Hz audio they can always resample it in an editor.
WARNING: preposterous time in Real Time Clock -- CHECK AND RESET THE DATE!

andreas_g

Thank you for the response. So I'll change recording to save the data before applying volume and filter. This change will be available in the next version of Previous.

Are there any audio experts in here? While trying to find out how to improve the low-pass filter I realized that in fact I need a de-emphasis filter for CD-standard emphasised sound. In real hardware the filter (analog implementation) is included in the Philips SAA7323 DAC inside the Soundbox. It is enabled via the DEC pin of the chip.

Does anyone have an idea how to implement de-emphasis for CD standard emphasised audio at 44,1 kHz?


ZombiePhysicist

I'm not expert.

I just asked some AI and it suggested what follows which may be garbage:


But maybe
  • [color=rgba(0, 0, 0, 0.96)]JUCE (C++)
    [/color]
    • [color=rgba(0, 0, 0, 0.96)]Cross‑platform, integrates with Core Audio on macOS. Use dsp::IIR::Coefficients anddsp::IIR::Filter (or dsp::ProcessorChain) for SOS processing; ready for plugin or standalone app.[/color]
[color=rgba(0, 0, 0, 0.96)]Ready-to-use coefficient approach (44.1 kHz)[/color]
  • [color=rgba(0, 0, 0, 0.96)]Use two first-order sections (cascade) converted via bilinear transform for τ = 50 µs and 15 µs.Implement as two 1st-order IIRs or combine into one biquad (SOS recommended).[/color]
[color=rgba(0, 0, 0, 0.96)]One combined biquad (Direct Form I, a0 = 1) for 44.1 kHz (use these in JUCE/vDSP/AudioUnit IIR APIs as b0,b1,b2 ; a0,a1,a2):[/color]
[color=rgba(0, 0, 0, 0.96)]b0 = 0.730944081 b1 = -1.432852847 b2 = 0.701908766 a0 = 1.000000000 a1 = -1.421865094 a2 = 0.711709612[/color]
[color=rgba(0, 0, 0, 0.96)]Implementation notes[/color]
  • [color=rgba(0, 0, 0, 0.96)]Use SOS/biquad routines (JUCE dsp::IIR, vDSP_biquadm, AudioUnit DSP code) to ensure numericstability.[/color]
  • [color=rgba(0, 0, 0, 0.96)]Normalize or verify 1 kHz reference gain if needed.[/color]
  • [color=rgba(0, 0, 0, 0.96)]Test with sweep and reference emphasis test tones.[/color]

Below is a minimal JUCE 7+ example demonstrating how to apply the de‑emphasis biquad in a standalone or plugin processor using JUCE's dsp::IIR::Filter. It loads the provided biquad coefficients into dsp::IIR::Coefficients and processes audio in processBlock.

Paste into your AudioProcessor's header/cpp or into a minimal JUCE Console/Audio plugin project.
Key points:
  • Sample rate must be 44100 Hz (coefficients precomputed for 44.1 kHz).
  • The coefficients are Direct Form I (a0 = 1) as b0,b1,b2 ; a0,a1,a2.


AudioProcessor.h (excerpt)

#pragma once

#include <JuceHeader.h>

class DeEmphasisProcessor  : public juce::AudioProcessor
{
public:
    DeEmphasisProcessor();
    ~DeEmphasisProcessor() override;

    void prepareToPlay (double sampleRate, int samplesPerBlock) override;
    void releaseResources() override;
    void processBlock (juce::AudioBuffer<float>&, juce::MidiBuffer&) override;

    // usual AudioProcessor boilerplate...
private:
    juce::dsp::IIR::Filter<float> deEmphasisFilter;
    JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (DeEmphasisProcessor)
};

AudioProcessor.h (excerpt)
#pragma once
#include <JuceHeader.h>

class DeEmphasisProcessor  : public juce::AudioProcessor
{
public:
    DeEmphasisProcessor();
    ~DeEmphasisProcessor() override;

    void prepareToPlay (double sampleRate, int samplesPerBlock) override;
    void releaseResources() override;
    void processBlock (juce::AudioBuffer<float>&, juce::MidiBuffer&) override;

    // usual AudioProcessor boilerplate...
private:
    juce::dsp::IIR::Filter<float> deEmphasisFilter;
    JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (DeEmphasisProcessor)
};

AudioProcessor.cpp (excerpt)
#include "AudioProcessor.h"

DeEmphasisProcessor::DeEmphasisProcessor()
{
    // constructor...
}

DeEmphasisProcessor::~DeEmphasisProcessor() = default;

void DeEmphasisProcessor::prepareToPlay (double sampleRate, int samplesPerBlock)
{
    juce::dsp::ProcessSpec spec;
    spec.sampleRate = sampleRate;
    spec.maximumBlockSize = static_cast<uint32> (samplesPerBlock);
    spec.numChannels = static_cast<uint32> (getTotalNumOutputChannels());

    deEmphasisFilter.reset();
    deEmphasisFilter.prepare(spec);

    // Ensure sample rate is 44.1 kHz (coeffs provided for 44100)
    if (std::abs(sampleRate - 44100.0) > 1.0)
    {
        // You can recompute coefficients for other rates; here we assert for clarity.
        jassertfalse;
    }

    // Coefficients (Direct Form I, a0 = 1)
    const double b0 = 0.730944081;
    const double b1 = -1.432852847;
    const double b2 = 0.701908766;
    const double a0 = 1.0;
    const double a1 = -1.421865094;
    const double a2 = 0.711709612;

    // JUCE expects coefficients as (b0,b1,b2,a0,a1,a2) for IIR::Coefficients::makeDirectFormI
    auto coeffs = juce::dsp::IIR::Coefficients<float>::makeDirectFormI(
        (float)b0, (float)b1, (float)b2, (float)a0, (float)a1, (float)a2);

    *deEmphasisFilter.state = *coeffs; // load coefficients into filter state
}

void DeEmphasisProcessor::releaseResources()
{
    deEmphasisFilter.reset();
}

void DeEmphasisProcessor::processBlock (juce::AudioBuffer<float>& buffer, juce::MidiBuffer&)
{
    juce::dsp::AudioBlock<float> block (buffer);
    juce::dsp::ProcessContextReplacing<float> context (block);

    // Process in-place (same coefficients used for all channels)
    deEmphasisFilter.process(context);
}





[color=rgba(0, 0, 0, 0.96)][color=var(--ds-text-primary)]Notes and suggestions[/color][/color]
  • [color=rgba(0, 0, 0, 0.96)][color=var(--ds-text-primary)]For different sample rates, recompute coefficients via bilinear transform or design an IIR from theanalog poles/zeros for the new sample rate.[/color][/color]
  • [color=rgba(0, 0, 0, 0.96)][color=var(--ds-text-primary)]For better numeric stability use an SOS cascade of first‑order sections (two 1st‑order filters) implement as two dsp::IIR::Filter instances in series.[/color][/color]
  • [color=rgba(0, 0, 0, 0.96)][color=var(--ds-text-primary)]In plugins, ensure processing is real‑time safe and avoid heavy allocations inprepareToPlay/processBlock.[/color][/color]
[color=rgba(0, 0, 0, 0.96)][color=var(--ds-text-primary)]If you want, I can generate:[/color][/color]
  • [color=rgba(0, 0, 0, 0.96)][color=var(--ds-text-primary)]the two 1st‑order section coefficients and an example chaining two dsp::IIR::Filter instances, or[/color][/color]
  • [color=rgba(0, 0, 0, 0.96)][color=var(--ds-text-primary)]code that recomputes coefficients at runtime for arbitrary sample rates. Which would you prefer?[/color][/color]





andreas_g

Thank you, but I generally do not use AI. It produces only garbage anyway. Previous is free from AI generated code.

Back to my question:
Does anyone know how to implement de-emphasis for CD standard emphasised audio at 44,1 kHz?

Protocol 7

You can find some info about CDDA de-emphasis here. Maybe it can lead in the right direction. SoX has a de-emphasis filter for example.

andreas_g

@Protocol 7
Thank you very much for the link. I had a look at cdda2wav and it seems to confirm my findings. I'll do some testing during the weekend.

andreas_g

I've added a new de-emphasis filter to the source repository now. It is derived from the math also used by cdda2wav and seems to sound as expected. Thank you for all help!

andreas_g

Hello all,

I am happy to release Previous v4.4! It adds support for saving prints and screenshots to TIFF files which can be opened by NeXTstep. It also improves PNG file saving the generate smaller file sizes. You might also notice improved efficiency when running a monochrome guest system as the screen drawing routine has been optimised. Another new feature is support for recording sound through the DSP serial port (sndrecord -d file.snd). Last but not least it replaces the bad low-pass filter for sound output with a more accurate de-emphasis filter (the filter is enabled by the guest system when playing emphasised audio).

As always I have built a binary for macOS 10.13 and later (Intel and Apple Silicon) which you can load here.

Have fun with the new version and please report any issues.

wmlive

Quote from: andreas_g on Jul 06, 2026, 06:39 AMI am happy to release Previous v4.4!
[...]
Have fun with the new version and please report any issues.
Thanks a lot, Andreas!

For the Linux based bug hunters, the Debian/Trixie packages for amd64/arm64/i386 at wmlive.rumbero.org/repo/pool/main/p/previous/ have been updated to release Previous v4.4 (r1847).

Rhetorica

#86
On the Windows side, it looks like we have some trouble.

I was not able to build an SDL2 (softfloat branch) binary for this release:

FAILED: src/gui-sdl/CMakeFiles/GuiSdl.dir/sdlaudio.c.obj
C:\Base\msys64\mingw64\bin\cc.exe -DCONFDIR=\".\" -DSDL_MAIN_HANDLED -ID:/Emulation/previous-src/pre
vious-r1847-softfloat/src/includes -ID:/Emulation/previous-src/previous-r1847-softfloat/src/debug -I
D:/Emulation/previous-src/previous-r1847-softfloat/src/dsp -ID:/Emulation/previous-src/previous-r184
7-softfloat/src/softfloat -ID:/Emulation/previous-src/previous-r1847-softfloat/src/dimension -ID:/Em
ulation/previous-src/previous-r1847-softfloat/src/slirp -ID:/Emulation/previous-src/previous-r1847-s
oftfloat/build -ID:/Emulation/previous-src/previous-r1847-softfloat/src/cpu -ID:/Emulation/previous-
src/previous-r1847-softfloat/src/gui-sdl/. -ID:/Emulation/previous-src/previous-r1847-softfloat/src/
gui-sdl/../.. -ID:/Emulation/previous-src/previous-r1847-softfloat/src/gui-sdl/../debug -ID:/Emulati
on/previous-src/previous-r1847-softfloat/src/gui-sdl/../includes -isystem C:/Base/msys64/mingw64/inc
lude/SDL2 -std=gnu99 -Wcast-qual -Wbad-function-cast -Wpointer-arith -Wmissing-prototypes -Wstrict-p
rototypes -Wall -Wwrite-strings -Wsign-compare -Wformat-security -g -O0 -D__USE_MINGW_ANSI_STDIO=1 -
Wno-conversion -Wimplicit-fallthrough=0 -Wshadow=local -Wvla -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS
=64 -Wno-write-strings -O3 -DNDEBUG -MD -MT src/gui-sdl/CMakeFiles/GuiSdl.dir/sdlaudio.c.obj -MF src
\gui-sdl\CMakeFiles\GuiSdl.dir\sdlaudio.c.obj.d -o src/gui-sdl/CMakeFiles/GuiSdl.dir/sdlaudio.c.obj
-c D:/Emulation/previous-src/previous-r1847-softfloat/src/gui-sdl/sdlaudio.c
D:/Emulation/previous-src/previous-r1847-softfloat/src/gui-sdl/sdlaudio.c: In function 'Audio_Output
_Queue_Put':
D:/Emulation/previous-src/previous-r1847-softfloat/src/gui-sdl/sdlaudio.c:38:46: error: passing argu
ment 1 of 'SDL_QueueAudio' makes integer from pointer without a cast [-Wint-conversion]
   38 |                 SDL_QueueAudio(audio_playback.device, data, len);
      |                                ~~~~~~~~~~~~~~^~~~~~~
      |                                              |
      |                                              SDL_AudioDeviceID * {aka unsigned int *}
In file included from C:/Base/msys64/mingw64/include/SDL2/SDL.h:36,
                 from D:/Emulation/previous-src/previous-r1847-softfloat/src/gui-sdl/sdlaudio.h:11,
                 from D:/Emulation/previous-src/previous-r1847-softfloat/src/gui-sdl/sdlaudio.c:13:
C:/Base/msys64/mingw64/include/SDL2/SDL_audio.h:1229:62: note: expected 'SDL_AudioDeviceID' {aka 'un
signed int'} but argument is of type 'SDL_AudioDeviceID *' {aka 'unsigned int *'}
 1229 | extern DECLSPEC int SDLCALL SDL_QueueAudio(SDL_AudioDeviceID dev, const void *data, Uint32 l
en);
      |                                            ~~~~~~~~~~~~~~~~~~^~~
D:/Emulation/previous-src/previous-r1847-softfloat/src/gui-sdl/sdlaudio.c: In function 'Audio_Output
_Queue_Size':
D:/Emulation/previous-src/previous-r1847-softfloat/src/gui-sdl/sdlaudio.c:44:65: error: passing argu
ment 1 of 'SDL_GetQueuedAudioSize' makes integer from pointer without a cast [-Wint-conversion]
   44 |                 int size = SDL_GetQueuedAudioSize(audio_playback.device);
      |                                                   ~~~~~~~~~~~~~~^~~~~~~
      |                                                                 |
      |                                                                 SDL_AudioDeviceID * {aka uns
igned int *}
C:/Base/msys64/mingw64/include/SDL2/SDL_audio.h:1311:73: note: expected 'SDL_AudioDeviceID' {aka 'un
signed int'} but argument is of type 'SDL_AudioDeviceID *' {aka 'unsigned int *'}
 1311 | extern DECLSPEC Uint32 SDLCALL SDL_GetQueuedAudioSize(SDL_AudioDeviceID dev);
      |                                                       ~~~~~~~~~~~~~~~~~~^~~
D:/Emulation/previous-src/previous-r1847-softfloat/src/gui-sdl/sdlaudio.c: In function 'Audio_Output
_Queue_Clear':
D:/Emulation/previous-src/previous-r1847-softfloat/src/gui-sdl/sdlaudio.c:57:52: error: passing argu
ment 1 of 'SDL_ClearQueuedAudio' makes integer from pointer without a cast [-Wint-conversion]
   57 |                 SDL_ClearQueuedAudio(audio_playback.device);
      |                                      ~~~~~~~~~~~~~~^~~~~~~
      |                                                    |
      |                                                    SDL_AudioDeviceID * {aka unsigned int *}
C:/Base/msys64/mingw64/include/SDL2/SDL_audio.h:1345:69: note: expected 'SDL_AudioDeviceID' {aka 'un
signed int'} but argument is of type 'SDL_AudioDeviceID *' {aka 'unsigned int *'}
 1345 | extern DECLSPEC void SDLCALL SDL_ClearQueuedAudio(SDL_AudioDeviceID dev);
      |                                                   ~~~~~~~~~~~~~~~~~~^~~
D:/Emulation/previous-src/previous-r1847-softfloat/src/gui-sdl/sdlaudio.c: In function 'Audio_Data_G
et':
D:/Emulation/previous-src/previous-r1847-softfloat/src/gui-sdl/sdlaudio.c:69:61: error: passing argu
ment 1 of 'SDL_DequeueAudio' makes integer from pointer without a cast [-Wint-conversion]
   69 |                         audio->size = SDL_DequeueAudio(audio->device, audio->data, sizeof(au
dio->data));
      |                                                        ~~~~~^~~~~~~~
      |                                                             |
      |                                                             SDL_AudioDeviceID * {aka unsigne
d int *}
C:/Base/msys64/mingw64/include/SDL2/SDL_audio.h:1277:67: note: expected 'SDL_AudioDeviceID' {aka 'un
signed int'} but argument is of type 'SDL_AudioDeviceID *' {aka 'unsigned int *'}
 1277 | extern DECLSPEC Uint32 SDLCALL SDL_DequeueAudio(SDL_AudioDeviceID dev, void *data, Uint32 le
n);
      |                                                 ~~~~~~~~~~~~~~~~~~^~~
D:/Emulation/previous-src/previous-r1847-softfloat/src/gui-sdl/sdlaudio.c: In function 'Audio_Input_
Buffer_Size':
D:/Emulation/previous-src/previous-r1847-softfloat/src/gui-sdl/sdlaudio.c:89:62: error: passing argu
ment 1 of 'SDL_GetQueuedAudioSize' makes integer from pointer without a cast [-Wint-conversion]
   89 |                 return SDL_GetQueuedAudioSize(audio_recording.device);
      |                                               ~~~~~~~~~~~~~~~^~~~~~~
      |                                                              |
      |                                                              SDL_AudioDeviceID * {aka unsign
ed int *}
C:/Base/msys64/mingw64/include/SDL2/SDL_audio.h:1311:73: note: expected 'SDL_AudioDeviceID' {aka 'un
signed int'} but argument is of type 'SDL_AudioDeviceID *' {aka 'unsigned int *'}
 1311 | extern DECLSPEC Uint32 SDLCALL SDL_GetQueuedAudioSize(SDL_AudioDeviceID dev);
      |                                                       ~~~~~~~~~~~~~~~~~~^~~
D:/Emulation/previous-src/previous-r1847-softfloat/src/gui-sdl/sdlaudio.c: In function 'Audio_Enable
':
D:/Emulation/previous-src/previous-r1847-softfloat/src/gui-sdl/sdlaudio.c:117:62: error: passing arg
ument 1 of 'SDL_GetAudioDeviceStatus' makes integer from pointer without a cast [-Wint-conversion]
  117 |                 if (bEnable && SDL_GetAudioDeviceStatus(audio->device) == SDL_AUDIO_PAUSED)
{
      |                                                         ~~~~~^~~~~~~~
      |                                                              |
      |                                                              SDL_AudioDeviceID * {aka unsign
ed int *}
C:/Base/msys64/mingw64/include/SDL2/SDL_audio.h:722:84: note: expected 'SDL_AudioDeviceID' {aka 'uns
igned int'} but argument is of type 'SDL_AudioDeviceID *' {aka 'unsigned int *'}
  722 | extern DECLSPEC SDL_AudioStatus SDLCALL SDL_GetAudioDeviceStatus(SDL_AudioDeviceID dev);
      |                                                                  ~~~~~~~~~~~~~~~~~~^~~
D:/Emulation/previous-src/previous-r1847-softfloat/src/gui-sdl/sdlaudio.c:120:51: error: passing arg
ument 1 of 'SDL_PauseAudioDevice' makes integer from pointer without a cast [-Wint-conversion]
  120 |                         SDL_PauseAudioDevice(audio->device, 0);
      |                                              ~~~~~^~~~~~~~
      |                                                   |
      |                                                   SDL_AudioDeviceID * {aka unsigned int *}
C:/Base/msys64/mingw64/include/SDL2/SDL_audio.h:785:69: note: expected 'SDL_AudioDeviceID' {aka 'uns
igned int'} but argument is of type 'SDL_AudioDeviceID *' {aka 'unsigned int *'}
  785 | extern DECLSPEC void SDLCALL SDL_PauseAudioDevice(SDL_AudioDeviceID dev,
      |                                                   ~~~~~~~~~~~~~~~~~~^~~
D:/Emulation/previous-src/previous-r1847-softfloat/src/gui-sdl/sdlaudio.c:121:70: error: passing arg
ument 1 of 'SDL_GetAudioDeviceStatus' makes integer from pointer without a cast [-Wint-conversion]
  121 |                 } else if (!bEnable && SDL_GetAudioDeviceStatus(audio->device) == SDL_AUDIO_
PLAYING) {
      |                                                                 ~~~~~^~~~~~~~
      |                                                                      |
      |                                                                      SDL_AudioDeviceID * {ak
a unsigned int *}
C:/Base/msys64/mingw64/include/SDL2/SDL_audio.h:722:84: note: expected 'SDL_AudioDeviceID' {aka 'uns
igned int'} but argument is of type 'SDL_AudioDeviceID *' {aka 'unsigned int *'}
  722 | extern DECLSPEC SDL_AudioStatus SDLCALL SDL_GetAudioDeviceStatus(SDL_AudioDeviceID dev);
      |                                                                  ~~~~~~~~~~~~~~~~~~^~~
D:/Emulation/previous-src/previous-r1847-softfloat/src/gui-sdl/sdlaudio.c:123:51: error: passing arg
ument 1 of 'SDL_PauseAudioDevice' makes integer from pointer without a cast [-Wint-conversion]
  123 |                         SDL_PauseAudioDevice(audio->device, 1);
      |                                              ~~~~~^~~~~~~~
      |                                                   |
      |                                                   SDL_AudioDeviceID * {aka unsigned int *}
C:/Base/msys64/mingw64/include/SDL2/SDL_audio.h:785:69: note: expected 'SDL_AudioDeviceID' {aka 'uns
igned int'} but argument is of type 'SDL_AudioDeviceID *' {aka 'unsigned int *'}
  785 | extern DECLSPEC void SDLCALL SDL_PauseAudioDevice(SDL_AudioDeviceID dev,
      |                                                   ~~~~~~~~~~~~~~~~~~^~~
D:/Emulation/previous-src/previous-r1847-softfloat/src/gui-sdl/sdlaudio.c: In function 'Audio_Open':
D:/Emulation/previous-src/previous-r1847-softfloat/src/gui-sdl/sdlaudio.c:150:31: error: assignment
to 'SDL_AudioDeviceID *' {aka 'unsigned int *'} from 'SDL_AudioDeviceID' {aka 'unsigned int'} makes
pointer from integer without a cast [-Wint-conversion]
  150 |                 audio->device = SDL_OpenAudioDevice(NULL, iscapture, &request, NULL, 0);
      |                               ^
D:/Emulation/previous-src/previous-r1847-softfloat/src/gui-sdl/sdlaudio.c: In function 'Audio_Close'
:
D:/Emulation/previous-src/previous-r1847-softfloat/src/gui-sdl/sdlaudio.c:181:43: error: passing arg
ument 1 of 'SDL_CloseAudioDevice' makes integer from pointer without a cast [-Wint-conversion]
  181 |                 SDL_CloseAudioDevice(audio->device);
      |                                      ~~~~~^~~~~~~~
      |                                           |
      |                                           SDL_AudioDeviceID * {aka unsigned int *}
C:/Base/msys64/mingw64/include/SDL2/SDL_audio.h:1490:69: note: expected 'SDL_AudioDeviceID' {aka 'un
signed int'} but argument is of type 'SDL_AudioDeviceID *' {aka 'unsigned int *'}
 1490 | extern DECLSPEC void SDLCALL SDL_CloseAudioDevice(SDL_AudioDeviceID dev);
      |                                                   ~~~~~~~~~~~~~~~~~~^~~
D:/Emulation/previous-src/previous-r1847-softfloat/src/gui-sdl/sdlaudio.c: In function 'Audio_Handle
_Disconnect':
D:/Emulation/previous-src/previous-r1847-softfloat/src/gui-sdl/sdlaudio.c:210:62: error: passing arg
ument 1 of 'SDL_GetAudioDeviceStatus' makes integer from pointer without a cast [-Wint-conversion]
  210 |         if (audio->freq > 0 && SDL_GetAudioDeviceStatus(audio->device) == SDL_AUDIO_STOPPED)
 {
      |                                                         ~~~~~^~~~~~~~
      |                                                              |
      |                                                              SDL_AudioDeviceID * {aka unsign
ed int *}
C:/Base/msys64/mingw64/include/SDL2/SDL_audio.h:722:84: note: expected 'SDL_AudioDeviceID' {aka 'uns
igned int'} but argument is of type 'SDL_AudioDeviceID *' {aka 'unsigned int *'}
  722 | extern DECLSPEC SDL_AudioStatus SDLCALL SDL_GetAudioDeviceStatus(SDL_AudioDeviceID dev);
      |                                                                  ~~~~~~~~~~~~~~~~~~^~~
D:/Emulation/previous-src/previous-r1847-softfloat/src/gui-sdl/sdlaudio.c:211:43: error: passing arg
ument 1 of 'SDL_CloseAudioDevice' makes integer from pointer without a cast [-Wint-conversion]
  211 |                 SDL_CloseAudioDevice(audio->device);
      |                                      ~~~~~^~~~~~~~
      |                                           |
      |                                           SDL_AudioDeviceID * {aka unsigned int *}
C:/Base/msys64/mingw64/include/SDL2/SDL_audio.h:1490:69: note: expected 'SDL_AudioDeviceID' {aka 'un
signed int'} but argument is of type 'SDL_AudioDeviceID *' {aka 'unsigned int *'}
 1490 | extern DECLSPEC void SDLCALL SDL_CloseAudioDevice(SDL_AudioDeviceID dev);
      |                                                   ~~~~~~~~~~~~~~~~~~^~~
[25/184] Building C object src/softfloat/CMakeFiles/SoftFloat.dir/softfloat.c.obj

Is it time to deprecate SDL2 (at least on Windows)? I'm not sure which branch @wmlive builds for i386.

Additionally, the filesharing branch binary fails to run, with:

The procedure entry point SDL_AudioStreamDevicePaused could not be located in the dynamic link library D:\Emulation\Previous_r1847-filesharing\previous.exe.

I assume these both pertain to a feature in a newer SDL3 build, in which case the outstanding problem with the main menu not refreshing the screen properly needs to be addressed before a Windows release can be made.

I've been shipping an outdated SDL3.dll that was more compatible, but it seems that will no longer suffice.

The compilation of the filesharing branch worked fine, aside from a warning about some possibly uninitialized variables in dlgMouse.c:

-- Build files have been written to: D:/Emulation/previous-src/previous-r1847-filesharing/build
[28/184] Building C object src/gui-sdl/CMakeFiles/GuiSdl.dir/dlgMouse.c.obj
In function 'Dialog_TabletDlg',
    inlined from 'Dialog_MouseDlg' at D:/Emulation/previous-src/previous-r1847-filesharing/src/gui-s
dl/dlgMouse.c:388:5:
D:/Emulation/previous-src/previous-r1847-filesharing/src/gui-sdl/dlgMouse.c:245:28: warning: 'after'
 may be used uninitialized [-Wmaybe-uninitialized]
  245 |         if (bTabletEnabled && (after != before)) {
      |             ~~~~~~~~~~~~~~~^~~~~~~~~~~~~~~~~~~~
D:/Emulation/previous-src/previous-r1847-filesharing/src/gui-sdl/dlgMouse.c: In function 'Dialog_Mou
seDlg':
D:/Emulation/previous-src/previous-r1847-filesharing/src/gui-sdl/dlgMouse.c:200:29: note: 'after' wa
s declared here
  200 |         TABLET_TYPE before, after;
      |                             ^~~~~
[184/184] Linking CXX executable src\previous.exe

I did not check the trunk branch—if I should be using it instead of filesharing, please remind me!

I have posted the 4.4 binaries for Mac and Debian to previous.nextcommunity.net. The Windows version will just have to be stuck at 4.3 until we get this sorted out.

Since this is partly (mostly?) my fault for not compiling every revision to catch this problem sooner, I will look into setting up some means of automating Windows builds on my workstation, though I cannot promise a specific timeline for that. I do already have an RSS feed that tells me when each update hits Sourceforge (this is how the forums know the current revision; I update it manually) but I have not yet taken the step of automating any actions based on it.
WARNING: preposterous time in Real Time Clock -- CHECK AND RESET THE DATE!

Rhetorica

Update: Built the trunk branch, no differences from the filesharing branch. The binary for r1847 runs with SDL 3.2.1 but not SDL 3.1.5. To reiterate why I've been stuck on such an old SDL version, Previous doesn't refresh the screen reliably when opening the menu with the F12 key. Later today I will try building a newer SDL3 to see if the behavior has improved.
WARNING: preposterous time in Real Time Clock -- CHECK AND RESET THE DATE!

wmlive

#88
Quote from: Rhetorica on Jul 06, 2026, 09:27 PMIs it time to deprecate SDL2 (at least on Windows)? I'm not sure which branch @wmlive builds for i386.
The builds for Debian (aka wmlive-trixie) are done using "libsdl3-0 (>= 3.2.0)" as included in Debian/Trixie.

Unless faulty memory deceives, SDL3 has officially become the default for Previous since a few releases already.
See https://nextcommunity.net/forums/index.php?msg=418 for reference.

Rhetorica

Yeah, I suppose I'll probably retire the SDL2 builds at this point entirely if the branch is no longer viable. I was keeping them going for the sake of completeness.
WARNING: preposterous time in Real Time Clock -- CHECK AND RESET THE DATE!