X Tutup
Skip to content

Linux support#28

Merged
squiggythings merged 75 commits intosquiggythings:mainfrom
Speykious:potential-linux-build
Jun 27, 2025
Merged

Linux support#28
squiggythings merged 75 commits intosquiggythings:mainfrom
Speykious:potential-linux-build

Conversation

@Speykious
Copy link
Contributor

@Speykious Speykious commented Sep 6, 2024

PR status

Some bugs have been pointed out, and they have been fixed. The PR is complete once again!

  • implement basic ALSA audio context
  • implement WAV file reader and writer
  • revive WAV export
  • replace WinForms with NativeFileDialogs.NET
  • configure sample rate
  • make sample browser functional again
  • enumerate and configure audio output devices
  • read MP3 and FLAC
  • implement MIDI input
  • add "save changes" dialog back (probably as a WaveTracker custom dialog window)
  • implement slightly more advanced text input (has been implemented already!)
  • revive StereoBiQuadFilter
  • maximize window on startup
  • make sure the Windows build isn't broken
    • implement mmsystem audio backend
    • MIDI input again?
    • keep system sounds playing on custom message dialogs
    • make sure embedded FFmpeg libraries are being found
  • make input fields actual input fields instead of spawning a dialogue? (has been implemented already!)

Bugs to fix:

  • app icon problem with DesktopGL
  • visual stutter occurring on high audio buffer length
    • Windows
    • Linux
  • random segfaults while previewing sample in sample file manager
    • Windows
    • Linux

Considerations

In #6 (comment), @tgpholly said that it would be more worthwhile contributing upstream to get better Linux support into NAudio. But I feel like instead it would be harder and take a longer time to implement, given how simple the audio interface can be for WaveTracker as far as I understand.

Explanations

For the implementation of the ALSA audio context, I'd like to mention this handy article on Minimal cross-platform graphics. I'd probably refer to it again for the Windows backend reimplementation, and it'll serve the same purpose eventually for MacOS.

The audio thread is incredibly simple, it just reads from the audio provider and writes to ALSA in a loop. Though I had to tweak the latency and sample buffer size to get results that sounded ok on my machine and didn't underrun too much, so I'm not sure about that. I think that'll probably become a setting.

As a full disclosure, I maintain NativeFileDialogs.NET and it binds to a C library (which isn't mine).

Edit: since then, the decision to use FFmpeg for audio file reading has been accepted. I decided to use FFmpeg 4.4. It's quite old, but the main benefit is that there is already an existing Nuget package - FFmpeg.Native - which automatically imports the libraries needed with the correct version. That way it's guaranteed that WaveTracker won't have any issue with loading them.

Here's a demo of sound, dialogs and WAV export working :D

wavetracker-linux-update.mp4

@squiggythings
Copy link
Owner

Thank you so much for your contributions. I hope my existing code isn't too messy or causing many problems!

If we could get cross platform audio output working without any of the windows-dependent NAudio libraries that would be a huge step forward. I think I might even separate out the logic that gathers and processes signals from all the channels in the AudioProvider.Read() loop into a function that just processes one sample's worth of audio and returns the resulting left and right values. Then that could just be linked into whatever code is feeding samples into the platform's audio buffer. I think that would be cleaner to separate the WaveTracker specific logic from the platform's audio API.

Right now I'm looking into modifying the custom input fields to accept text input, highlighting, arrow key cursor navigation, all the things you'd expect an input field to have; which, granted, is quite a lot. I think this will be the biggest roadblock towards getting the app to be cross platform, so I'd like to start chipping away at it now. Of course there are cross platform alternatives to winforms that could replace the pop-up dialog in an emergency, but I'd really really really like to have seamless field editing without opening up an ugly pop up. (It would also allow for searching in the sample browser!)

@Speykious
Copy link
Contributor Author

Thank you so much for your contributions. I hope my existing code isn't too messy

So far I honestly expected all of this to be much harder than it actually was. To the contrary I find your code pretty readable and well-organized xd

@HotoRas
Copy link

HotoRas commented Sep 7, 2024

👀

@Speykious
Copy link
Contributor Author

Speykious commented Sep 7, 2024

Audio devices! (ALSA description names are quite verbose...)

Edit: there's a bunch of duplicates, I think I might filter out any device that isn't strictly an I/O device (pretty much all the duplicates I have here are output-only).
image

@darkhog
Copy link

darkhog commented Sep 7, 2024

You could also just filter out actual duplicates (check if the name is the same as existing device on the list, if so skip adding it to the list). I think LMMS (open source FL Studio clone) does it that way.

@Speykious
Copy link
Contributor Author

Speykious commented Sep 7, 2024

I'm just not exactly sure how to know it's a duplicate, because both the full description and name are always different from each other. The output-only stuff is just a pattern I noticed...

Full print of my PCM devices

Here's a print of my PCM devices, in the following format:

[I/O] name
  description

The description can span several lines, and I and O are absent if the device doesn't do input/output respectively.

[I/O] null
  Discard all samples (playback) or generate zero samples (capture)

[I/O] lavrate
  Rate Converter Plugin Using Libav/FFmpeg Library

[I/O] samplerate
  Rate Converter Plugin Using Samplerate Library

[I/O] speexrate
  Rate Converter Plugin Using Speex Resampler

[I/O] jack
  JACK Audio Connection Kit

[I/O] oss
  Open Sound System

[I/O] pipewire
  PipeWire Sound Server

[I/O] pulse
  PulseAudio Sound Server

[I/O] speex
  Plugin using Speex DSP (resample, agc, denoise, echo, dereverb)

[I/O] upmix
  Plugin for channel upmix (4,6,8)

[I/O] vdownmix
  Plugin for channel downmix (stereo) with a simple spacialization

[I/O] default
  Default ALSA Output (currently PipeWire Media Server)

[ /O] hdmi:CARD=HDMI,DEV=0
  HDA ATI HDMI, HDMI 0
  HDMI Audio Output

[I/O] usbstream:CARD=HDMI
  HDA ATI HDMI
  USB Stream Output

[ /O] hdmi:CARD=Generic,DEV=0
  HD-Audio Generic, HDMI 0
  HDMI Audio Output

[I/O] usbstream:CARD=Generic
  HD-Audio Generic
  USB Stream Output

[I/O] sysdefault:CARD=Generic_1
  HD-Audio Generic, ALC294 Analog
  Default Audio Device

[I/O] front:CARD=Generic_1,DEV=0
  HD-Audio Generic, ALC294 Analog
  Front output / input

[ /O] surround21:CARD=Generic_1,DEV=0
  HD-Audio Generic, ALC294 Analog
  2.1 Surround output to Front and Subwoofer speakers

[ /O] surround40:CARD=Generic_1,DEV=0
  HD-Audio Generic, ALC294 Analog
  4.0 Surround output to Front and Rear speakers

[ /O] surround41:CARD=Generic_1,DEV=0
  HD-Audio Generic, ALC294 Analog
  4.1 Surround output to Front, Rear and Subwoofer speakers

[ /O] surround50:CARD=Generic_1,DEV=0
  HD-Audio Generic, ALC294 Analog
  5.0 Surround output to Front, Center and Rear speakers

[ /O] surround51:CARD=Generic_1,DEV=0
  HD-Audio Generic, ALC294 Analog
  5.1 Surround output to Front, Center, Rear and Subwoofer speakers

[ /O] surround71:CARD=Generic_1,DEV=0
  HD-Audio Generic, ALC294 Analog
  7.1 Surround output to Front, Center, Side, Rear and Woofer speakers

[I/O] usbstream:CARD=Generic_1
  HD-Audio Generic
  USB Stream Output

[I/O] sysdefault:CARD=Microphones
  Blue Microphones, USB Audio
  Default Audio Device

[I/O] front:CARD=Microphones,DEV=0
  Blue Microphones, USB Audio
  Front output / input

[ /O] surround21:CARD=Microphones,DEV=0
  Blue Microphones, USB Audio
  2.1 Surround output to Front and Subwoofer speakers

[ /O] surround40:CARD=Microphones,DEV=0
  Blue Microphones, USB Audio
  4.0 Surround output to Front and Rear speakers

[ /O] surround41:CARD=Microphones,DEV=0
  Blue Microphones, USB Audio
  4.1 Surround output to Front, Rear and Subwoofer speakers

[ /O] surround50:CARD=Microphones,DEV=0
  Blue Microphones, USB Audio
  5.0 Surround output to Front, Center and Rear speakers

[ /O] surround51:CARD=Microphones,DEV=0
  Blue Microphones, USB Audio
  5.1 Surround output to Front, Center, Rear and Subwoofer speakers

[ /O] surround71:CARD=Microphones,DEV=0
  Blue Microphones, USB Audio
  7.1 Surround output to Front, Center, Side, Rear and Woofer speakers

[ /O] iec958:CARD=Microphones,DEV=0
  Blue Microphones, USB Audio
  IEC958 (S/PDIF) Digital Audio Output

[I/O] usbstream:CARD=Microphones
  Blue Microphones
  USB Stream Output

Edit: now that I look at it again, the remaining duplicates (if I ignore the [ /O] ones) are sysdefault: ones, which makes sense.

@Speykious
Copy link
Contributor Author

Speykious commented Sep 8, 2024

So... I realized that NAudio.Core actually contains the DirectSound output implementation that links to Windows libs. In the future I might contribute to NAudio to at least make sure the Windows-specific classes get a [SupportedOSPlatform("Windows")], but I'm not really confident in importing NAudio as sit stands so for now I'm copying classes over when I can. I don't think WaveTracker uses many features of NAudio anyway so it shouldn't end up being too many classes.

Edit: I had another realization, SupportedOSPlatform isn't available in the netstandard2.0 target...

@Speykious
Copy link
Contributor Author

The sample browser is now functional again but I really don't like the code I've written for that to happen... I'll see if it's still bearable when I add MP3 and FLAC parsing somehow, but even then I'd love feedback and ideas on that when I'm done.

As it stands, depending on NAudio is not favorable because it has a strong dependency on Windows. Since adding cross-platform support to NAudio will likely take much more time than implementing what's necessary for WaveTracker, vendoring NAudio.Midi is favorable as long as NAudio remains Windows-specific.
@Speykious
Copy link
Contributor Author

Nevermind, clipping still appears after running the app for about 1 minute... Not sure what to do about it.

@squiggythings
Copy link
Owner

Finally getting a chance to take a look now. Everything seems to be working okay on windows except for a crash I sometimes get when previewing samples in the sample browser. Not sure exactly what's causing it but I'm going to try to see if I can find out.

@Speykious
Copy link
Contributor Author

Thank you! I've noticed it as well. There's probably some low-level thing I've written in there that isn't quite sound/safe, although I didn't manage to find the problem. I'd say the best places to look are the audio engine implementations.

@Speykious
Copy link
Contributor Author

Ok, it seems I haven't been careful enough with my audio engine. It's writing in the audio thread but changing the sample rate on the main thread. I'll try to think of the best way to have everything related to managing the audio output on a single thread.

@Speykious
Copy link
Contributor Author

I still have to test on Windows but I at least fixed the crash on Linux

@Speykious
Copy link
Contributor Author

I fixed it yesterday on Windows, I think it should be good now

@squiggythings
Copy link
Owner

Great news! Hopefully I'll get a chance to take a look this weekend

@peppidesu
Copy link

Hi, what things still need to happen for this to be merged?

@Astralchroma
Copy link

I don't think anything needs to be done right now. Just it needs to be looked over.

@user0-07161
Copy link

Linux user here. NativeFileDialogs doesn't work.

Unhandled exception. NativeFileDialogs.Net.NfdException: The name is not activatable
   at NativeFileDialogs.Net.ResultExtensions.ToNfdStatus(Result result)
   at NativeFileDialogs.Net.Nfd.OpenDialog(String& outPath, IDictionary`2 filters, String defaultPath)
   at WaveTracker.SaveLoad.<>c__DisplayClass53_0.<SetFilePathThroughOpenDialog>b__0() in /home/user0/WaveTracker/WaveTracker/Source/Tracker/SaveLoad.cs:line 477

@user0-07161
Copy link

user0-07161 commented Apr 10, 2025

I honestly think GtkSharp's filechooser implementation works better here as NativeFileDialogs is pretty unmaintained.

@Speykious
Copy link
Contributor Author

Hey, I maintain NativeFileDialogs.NET, so if there's a problem I can try fixing it xd
I'll look into that bug in a few days

@user0-07161
Copy link

Ah, yeah, would be nice. Also nevermind about using GtkSharp, NFD is much more lightweight and does not depend on GTK so that's better.

@user0-07161
Copy link

Anyway, this PR is great work, really like it

@Speykious
Copy link
Contributor Author

Very late update on this bug: I just can't reproduce it. If it manages to come up again in the future I'll make a future PR I guess

@squiggythings
Copy link
Owner

My apologies for being sooo behind on this, life has been very busy the past few months. Finally taking a look now, all seems to be good. Going to merge this to be bundled in with some other changes/bug fixes I'd like to include in the next release.

Huge thank you to Speykious and everyone here who contributed

@squiggythings squiggythings merged commit 741575c into squiggythings:main Jun 27, 2025
@Speykious
Copy link
Contributor Author

Thank you so much!!

Do mention me on issues if any problem with the audio engine or something along those lines resurface.

@RubberDuckyDJ
Copy link

@Speykious You actually rock so much.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Feature Request] Linux version?
X Tutup