-
Notifications
You must be signed in to change notification settings - Fork 8.4k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Reimplement DECPS using DirectSound in place of MIDI #13471
Conversation
{ | ||
if (SUCCEEDED(DirectSoundCreate8(nullptr, &_directSound, nullptr))) | ||
{ | ||
if (SUCCEEDED(_directSound->SetCooperativeLevel(windowHandle, DSSCL_NORMAL))) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can ServiceLocator::LocateConsoleWindow()->GetWindowHandle()
return null?
Should we add the sample code from the remarks here?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can
ServiceLocator::LocateConsoleWindow()->GetWindowHandle()
return null?
I don't think so. Technically it could be null briefly during startup, but the ConsoleAllocateConsole
call blocks until InitWindowsSubsystem
is done (that's where the window gets created). And if the window couldn't be created for some reason, then the ConsoleAllocateConsole
call would fail, and there simply wouldn't be a console.
In conpty mode it's different. In that case ServiceLocator::LocateConsoleWindow
itself would return null, but we also would never get this far, because the DECPS
sequence would be passed through to the conpty client instead.
{ | ||
midiOut.OutputMessage(MidiOut::NOTE_ON, noteNumber, velocity); | ||
// The formula for frequency is 2^(n/12) * 440Hz, where n is zero for |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
thank you for these comments
Hello @zadjii-msft! Because this pull request has the p.s. you can customize the way I help with merging this pull request, such as holding this pull request until a specific person approves. Simply @mention me (
|
@@ -1342,7 +1342,8 @@ namespace winrt::Microsoft::Terminal::Control::implementation | |||
{ | |||
if (!_midiAudio) | |||
{ | |||
_midiAudio = std::make_unique<MidiAudio>(); | |||
const auto windowHandle = reinterpret_cast<HWND>(_owningHwnd); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
note for @zadjii-msft: this will need to be changed when tearout changes the owning HWND
Thanks for doing this! I'm looking up It's interesting to note that the MIDI version had somewhat of an instrumental quality to it, whereas this one is very much more "simple tones." I am not sure which is better! |
I think the MIDI version handled the note separation better than my hack for this, but I actually prefer the simple sound of this one. Although we can tweak that sound fairly easily if you want to try something else - you just change the |
## Summary of the Pull Request The original `DECPS` implementation made use of the Windows MIDI APIs to generate the sound, but that required a 3MB package dependency for the GS wavetable DLS. This PR reimplements the `MidiAudio` class using `DirectSound`, so we can avoid that dependency. ## References The original `DECPS` implementation was added in PR #13208, but was hidden behind a velocity flag in #13258. ## PR Checklist * [x] Closes #13252 * [x] CLA signed. * [ ] Tests added/passed * [ ] Documentation updated. * [ ] Schema updated. * [x] I've discussed this with core contributors already. Issue number where discussion took place: #13252 ## Detailed Description of the Pull Request / Additional comments The way it works is by creating a sound buffer with a single triangle wave that is played in a loop. We generate different notes simply by adjusting the frequency at which that buffer is played. When we need a note to end, we just set the volume to its minimum value rather than stopping the buffer. If we don't do that, the repeated starting and stopping tends to produce a lot of static in the output. We also use two buffers, which we alternate between notes, as another way to reduce that static. One other thing worth mentioning is the handling of the buffer position. At the end of each note we save the current position, and then use an offset from that position when starting the following note. This helps produce a clearer separation between tones when repeating sequences of the same note. In an ideal world, we should really have something like an attack-decay- sustain-release envelope for each note, but the above hack seems to work reasonably well, and keeps the implementation simple. ## Validation Steps Performed I've manually tested both conhost and Terminal with the sample tunes listed in issue #8687, as well as a couple of games that I have which make use of `DECPS` sound effects. (cherry picked from commit bc79867) Service-Card-Id: 84270205 Service-Version: 1.15
🎉 Handy links: |
Summary of the Pull Request
The original
DECPS
implementation made use of the Windows MIDI APIs togenerate the sound, but that required a 3MB package dependency for the
GS wavetable DLS. This PR reimplements the
MidiAudio
class usingDirectSound
, so we can avoid that dependency.References
The original
DECPS
implementation was added in PR #13208, but washidden behind a velocity flag in #13258.
PR Checklist
where discussion took place: We might need another dependency for MIDI support #13252
Detailed Description of the Pull Request / Additional comments
The way it works is by creating a sound buffer with a single triangle
wave that is played in a loop. We generate different notes simply by
adjusting the frequency at which that buffer is played.
When we need a note to end, we just set the volume to its minimum value
rather than stopping the buffer. If we don't do that, the repeated
starting and stopping tends to produce a lot of static in the output. We
also use two buffers, which we alternate between notes, as another way
to reduce that static.
One other thing worth mentioning is the handling of the buffer position.
At the end of each note we save the current position, and then use an
offset from that position when starting the following note. This helps
produce a clearer separation between tones when repeating sequences of
the same note.
In an ideal world, we should really have something like an attack-decay-
sustain-release envelope for each note, but the above hack seems to work
reasonably well, and keeps the implementation simple.
Validation Steps Performed
I've manually tested both conhost and Terminal with the sample tunes
listed in issue #8687, as well as a couple of games that I have which
make use of
DECPS
sound effects.