Code Monkey home page Code Monkey logo

snestracker's Introduction

SNES Tracker

Build Status

SNES Tracker logo

SNES Tracker aims to become a full-featured cross-platform music production software for the Super Nintendo Entertainment System (SNES), aka the Super Famicom.

Visit the SNES Tracker Youtube for an example of the music that you can make with the latest version.

SNES Tracker early prototype preview

SPC Debugger

SNES Tracker also sports its own SPC debugger. See Debugger.md for more details.

Road Map

Coming soon, Roadmap.md

Downloads

Three flavours of pre-built SNES Tracker binaries are available for you!

  • OLD: simply download from the Releases Page.
  • LATEST: With any purchase from the Gift Shop you'll receive a one-time instant download link to the latest version of SNES Tracker.
  • LATEST+INTERIM: As a thank you to my Patreon Supporters, who help to keep this project going, the latest version of SNES Tracker is available exclusively via Patreon a few weeks before it becomes available on github. Support me and this project by becoming a Patreon Supporter and you will not only receive a download link to the latest stable version each time it is released - you'll also unlock access to the very latest interim builds, experience up-to-the-minute bug fixes, features and improvements weeks before anybody else. Aside from builds access, you can also earn privileged roles in our Discord community, receive generous shop discounts, exclusive behind the scenes updates, and more!

The following downloads are available:

  • Windows 7 (64-bit) and newer
  • MacOS 10.9 and newer
  • Linux users are encouraged to build from source or run the Windows build under WINE until a Linux build is released.

For more information on building SNES Tracker yourself, see Building.md

How To

See the Wiki to learn more about how to use and enjoy SNES Tracker from our ever-expanding knowledge base! If you get stuck, join our community (link below) to make helpful, friendly connections.

Community

Feel free to join the new SNES Tracker Discord Server. You may also join via IRC. Server: irc.esper.net Channel:#snestracker

The Discord and IRC are bridged by snesbot :)

Supporting

I hope that you love what I'm doing with SNES Tracker. You see, SNES Tracker is still a program that needs a lot of tender, loving care. If you would like to get more involved, please take a look at my new Patreon and/or make a visit to the Gift Shop to find yourself something you'd appreciate having that also helps keep the project alive!

T-Shirt Preview

Contributing

Contributions from the community are valid and welcome! For those curious about getting involved, have a look at Good First Issues. If you see an issue that appeals to you, post a comment demonstrating your interest. You are also encouraged to join the Discord or IRC. Be interactive! Together we will learn, grow, and make snestracker the best it can be.

By contributing, you acknowledge you have read and agreed to the Fine Print

Links

Youtube Subscribe and hit that notification bell for exclusive SNES Tracker songs, insight and out-of-this-world SNES-related fun.

Gift Shop Browse for fun SNES Tracker products! Support the project, in style, with branded goodies such as mugs and tshirts! Show the world your SNES obsession!

Soundcloud Listen to official tunes and remixes.

Wiki Learn more about how to use and enjoy SNES Tracker from our ever-expanding knowledge base.

Twitter Be first to get instant news and musings on upcoming features and new software releases.

By Bazz

Developed by Bazz, [email protected]

Special thanks to Blargg & Raph.

Shoutout to byuu, Neviksti, mukunda (eKid), Oli (Vilxdryad), RowanDDR, and the snesdev community!

snestracker's People

Contributors

bazz1tv avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

snestracker's Issues

[std] BRR Rip

When Rowen used the midithread2.zip, he was unable to get a dialogue box in std to rip BRR from either the DSP or MEM tabs.

However, he was able to get Open File dialogues from snestracker. Investigate if a newer version of the binary works. Discover if Windows 10 needs more care.

Perhaps look at a newer version of NFD (native file dialogue)

[PatternEditor] cursor bug when switching to pattern of less rows

To Reproduce:

  • Create one pattern (00) with default length $40.
  • Create another pattern (01), but this time set the length to much lower.
  • Now, while in pattern (01), click the cursor on a high numbered row near the bottom of the screen. The highlight bar should move there as normal.
  • Finally, switch back to pattern (00). The highlight bar stays floating in black space because pattern (00) doesn't have as many rows.

Solution: Add some logic when switching rows.

(Pardon the horrid scaling in the photos)
Screen Shot 2020-06-06 at 9 13 13 AM -> Screen Shot 2020-06-06 at 9 13 49 AM

Comments in the Pattern Editor

Let's face it, pattern data can become a mundane mess. To make this easier to manage and understand, allow the user to add comments. Requested by @RowanDDR.

What follows is a brain storm on impl'ing the feature.

The comments will go become metadata, perhaps easiestly impl'd in the PatternMeta class or by creating a TrackRowMeta class.

Somehow (right clicking over a row and getting a context menu including the option to add a comment), the user can add a comment to a row on the active pattern in the pattern editor. When this is activated, a variation on a TextEditRect should appear, take focus, and allow the user to write in their comment.

In order not to compete with the tracker arrangement, comments could behave like tooltips, in that they are simply an icon that you must click on to reveal the comment.

The comment, when revealed, needs a button to edit it or remove it. (right clicking on the comment should produce a context menu allowing the same).

I want a comment icon, small enough to fit in a row, cool enough to attract some.attention.

Comments should be expandable. When expanded, they take up a row of space. The pattern editor logic will need to use that for its calculations of the layout.

We can decide to save the state of comments when the project is saved. Eg. Which comments are expanded (when that gets impl'd).

Comments could be allowed per track, but since that increases initial complexity, let's first implement per row.

The user may want to permanently display their comment in the patterneditor. Consider how this might be implemented after getting the initial impl done.

[std] [feat-req] Upload BRR

Thought of by @RowanDDR

Enable std to upload BRR into DIR slots for spc modification. Some brief thoughts on this

  • Compute size of the existing BRR sample (Brr class has a size() function for this), and compare with the size of the new BRR. If it's bigger, warn the user of the risk of corrupting surrounding data with a YES/NO dialogue.

IT could be as simple as the above. OR you could get fancier by running a record on which additional BRR slots were taken up by a warned upload. Then, when the user tries to upload directly to one of these "taken" slots, they could be warned that it would damage one of their own uploaded samples!

The GUI should use that record to visually display which BRRs have been overwritten during the session. This could take the form of rendering the font in a different color or assigning an icon next to pertinent DIR entries.

Unfortunately this record won't normally persist once the file has been closed. That can be addressed in a later endeavor (or ignored forever). But here are some brief thoughts on that too: For that, some additional metadata would need to be recorded to an additional file (or somehow transparently into the SPC itself, but that could risk becoming unreadable by other SPC software).

Clicking in Options Window causes InstPanel artifact in Main Window

1eaf9e06b76618af2c7633cc4bdd930d

Scenario
After clicking Edit->Options from the Main Window, the options window appears. After clicking anywhere in the window, it causes the lines of the Instrument panel to become slightly removed (as pictured).

Expected Behavior

No modification to the main window whatsoever.

Well that's strange, but it became apparent that snestracker is not doing a good job of differentiating mouse and keyboard interaction between windows. That might be the root cause of this (?).

integrate kbd shortcuts...

Integrate the keyboard shortcuts into a new struct including a string description. This will improve organization, be self-documenting, and lay the foundation for user-customizable shortcuts from the GUI options menu.

It could be implemented similar to the upcoming FileLoader family of classes, such that there is a static data member like a vector that builds up a list of instances. In this case providing access into each module's kbd shortcuts.

At the same time, each module only deals with its own set of shortcuts.

Having the instance collection enables clash checks. Implement "global" clash checking across all modules.

but ideally duplicate shortcuts would be allowed for modules that are never simultaneously active. (seems overly complex for the scope of this app).

This class also needs a string identifying the module it belongs to (eg Pattern Editor), and a priority_hint to suggest its appearance order on the GUI options menu.

In the options menu kbd shortcut editor, the shortcuts can be divided by modules via tabs (implementation present) or trees (not yet implemented).

I remember enjoying BSNES' design of kbd shortcuts, but it seems I got this under control.

Confirm on Close

A dialogue box asking to confirm on close would reduce the amount of lost work, I only lost an instrument but I'd imagine it could be worse.

[options] gracefully deal with disconnected audio devices

The program should behave appropriately concerning audio devices that were probed at program startup but have since been removed / disabled / unplugged. In my experience the program will hang when trying to select such an outdated device from the options window. Here's a couple suggestions:

  • Query available audio devices when options window is activated (to get most recent list)
  • (optional) Periodically query audio devices available
  • When user selects an audio device, check that it's valid somehow before attempting to open it (eg. with SDL_OpenAudioDevice).

One way to check the validity of the device name would be to re-query when selecting the device.

Add option for Decimal / Hex

Depends on #50 (checkbox). Tied to #52.

Once again, not everyone is a coder. Not everyone understands hex. Allow for decimal / hex toggle option. Should affect the UI display of:

  • sample panel indices
  • instrument panel indices
  • sample editor valuez
  • instrument editor values
  • song settings values
  • SPD / ADD values
  • pattern editor indices
  • pattern sequencer indices
  • pattern sequencer pattern numbers.

(not worded.correctly yet, but) Need to decide how to best tie the classes that represent this data, with the UI settings without trashing having data structures indepedent of the UI. Some data structures are already UI exclusive, which is good, such as SamplePanel and InstrumentPanel. Maintain that sort of GUI collection of.classes on top of the core data.

can click menubar from spc export window

While in the File->Export SPC window, Clicking on the ':' after GAME will actually cause a click on the Main Window's menu bar "Edit" button. This seems because it's mapping the relative window coordinates and sending events to the Main Window event handler even when focused on the sub window.

The root of the problem is related to #15 and #16.

Double Click in Options Window causes Sparkles on Main Window

Scenario

Double clicking inside the options window causes the sparkle animation to appear on the Main Window.

Expected Behavior

I expected to see the sparkles under the cursor as they usually appear.

The solution

Track a reference to the active window, and have the mouse animations use specifically that window's renderer when drawing the textures. Fortunately most of that is already being tracked from the Event loop :) should be an easy impl

Create an Experience pipeline

The Experience class is a OOP code structure that houses render and event processing. You could consider it the view and controller of MVC. (this brings to mind whether or not these two should be tightly coupled. But that's for another day).

Suffice it to say most of the graphical on-screen elements draw() and handleEvent(). (I like this naming convention because they are both verbs. But in reality the event handling function is called event_handler() or handle_event(). Admittedly, there needs to be more consistency here. Another issue will be filed for this).

Now the current coding process for GUI elements is cumbersome. A large list of calls get bunched discretely into separate parts of the parent object. Namely, these separate parts are the draw function and also the event handler.

Wouldn't it be nice if the parent of all these GUI instances could simply add them to a pipeline from just one place? This would reduce coding aggravation inside the parent, turning a fragmented set of calls for every single element to a simple iterator on all of the objects in the pipeline. This can be done as an Experience (coupled drawing and event handling class), or only for Drawings, or only for EventListeners.

Z Indexing

One consideration is to add a zIndex component to the Drawings. It would be used just like CSS z-index. This allows translating the order of draw operations in the current implementation to something that can work in the pipeline method. Now, there may be better methods of organizing the order of pipeline objects, but this is simple and harks back to the SNES.

In order to keep pipeline members sorted by their z-index, I propose 2 solutions:

  1. a sorted insert
  2. Maintain a fixed size array of pipeline objects, where the index represents z-index. (harking back to snes!).

Code

Restructure existing GUI classes that already combine their Model data with their Experience calls (draw, event_handler). I want the model to be its own class. The actual final GUI element will combine the model with the Experience through inheritance.

Go this way through the gui modules in pc/shared/gui.

Then establish the pipeline. Because it harkens to snes, I elect to use the fixed size z-indexed pipeline. Well I don't want to write the code here for you! Haha

Eventually it will become clear whether the Experience pipeline needs to be broken up into a Drawing and EventListener pipeline. It's probably best to just do this from the start, since you'll have to go back to the GUI modules.

Well, that's plenty to get you started.

[std] realtime SRCN preview

For any SRCN that has been played, offer a "preview" in the right-click context menu. The song-time of preview and duration of preview will need to be intelligently calculated and user-adjustable.

Cannot build on Linux: missing pcx2snes

Hi all,

I'm attempting to follow the guide for building this project, but the Makefile is attempting to run a program called pcx2snes, which doesn't seem to exist in this project or in any package. I tried using the one from optixx (https://github.com/optixx/snes/tree/master/vram/tools), but a) it seems only to be for windows, and b) I get mysterious "File not found" pop-up boxes when I attempt to use it through wine. My setup for wine is just an executable script on the PATH called pcx2snes with the contents:

#!/bin/bash
exec wine /path/to/pcx2snes.exe "$@"

Any tips on how I'm recommended to install this tool? I've come up blank unfortunately.

SDL_GetBasePath() on Linux installation not sufficient

I'm currently cobbling together a test-expression for including snestracker in Nixpkgs, and I'm running into some problems. One of them being the use of SDL_GetBasePath() to find assets, which doesn't play nice with the way these are usually spread out on a Linux system.

(The way package contents are usually distributed in the Linux FHS)
  • Binaries get moved to a /bin directory under a prefix, e.g. /bin with an empty prefix, /usr/local/bin with prefix /usr/local. In the case of Nix, this would be something like /nix/store/<hash>-snestracker-unstable-20200610/bin/

  • Global assets get moved to a /share directory under said prefix. Where exactly they end up depends on their specific use-case, but application-specific assets often go to $prefix/share/<applicationName>. For instance, I'm moving the cursors directory and tracker.spc to /nix/store/<hash>-snestracker-unstable-20200610/share/snestracker/

When std starts up, it calls SDL_GetBasePath() to find the cursor assets. SDL_GetBasePath() however leads to the directory the executable resides in, which in a properly system-installed package is not where the assets would reside in.

My really ugly workaround right now is keeping the binaries in /share/snestracker and symlinking them into the appropriate /bin directory, which gets the application further but seemingly nowhere near a proper launch. Are there plans to improve this? A simple ../share/snestracker/ appended to the path returned by SDL_GetBasePath() via an ifdef + instructions for packagers to put the assets in such a relative directory would be a quite simple fix for this particular problem, but maybe there are smarter ways of solving this.

Add git commit hash to build number

In order to keep track of binary versions, do as titled.

After some research ( https://stackoverflow.com/questions/6526451/how-to-include-git-commit-number-into-a-c-executable ), it seems the best way is to add some steps at the beginning of the linker stage in Makefile.

# pipe declaration of string constant into gcc for compilation as an object file

# link as normal

Then in source code organization.h, add an extern to that linked variable.

snestracker will then have a version output like
"v0.1.0-123bcd" Signifying the predominant version and commit.

There should also be a compile-time Toggle to not include the hash when providing the version string.

[st] Change Audio Output Device causes song playback

Prerequisites:

  • song playback has already been performed, then stopped
  • Change the audio output device from Edit->Options window

Expected Behavior

The audio output device is changed, but the song remains in whatever playback mode it was already in (in this case, stopped).

Actual Behavior

The audio output device is changed, and then the song starts playing back.

Log

2020-05-23 15:40:23.885 st[24422:311729] INFO: Audio_Options::receive_event
MEEP2020-05-23 15:40:23.885 st[24422:311729] INFO: change_audio_out_device, Built-in Output
Music_Player::init
samples = 2048
audio buffs per sec = 15.62
Opening Audio out Device: Built-in Output
aspec size = 8192
Window 2 Lost keyboard focus

This bug occurred on Mac OSX, but is expected to be multiplatform

Related

Stemming from the above problem, if after playing a song with several patterns, a new song or song with less patterns is loaded, changing the audio device at that point will somehow cause an ASSERT on pattern position < patternlength to fail.. But I think these problems will disappear once I fix the root of the problem

Music_Player::init
samples = 2048
audio buffs per sec = 15.62
Opening Audio out Device: Soundflower (2ch)
aspec size = 8192
Assertion failed: (row < patseq->num_entries), function set_currow, file tracker/Pattern.cpp, line 415.
Abort trap: 6

[std] Save ADSR info of every SRCN throughout song playback

This would be done to

  • Allow accurate dumping of a SRC at any time (provided it's been used at least once).
  • Possibly track multiple ADSR settings for a single SRCN.

If a SRCN hasn't been played yet and the user attempts to dump STI (snestracker instrument), notify the user of this and provide a quick solution (eg. lightning-fast playback until SRCN has been used, then dump).

If multiple ADSR settings are present, they can be saved into STI and be later all imported into snestracker. But, Multiple ADSR settings per instrument would be a seperate enhancement to discuss in the future.

Cleanup build warnings

There are lots of compiler warnings. LOTS. LOTS.

Simply pick a module that has some warnings and take it one source file at a time. Most warnings are a simple fix, while others may deserve more care.

I'm going to mark this issue as a "good first issue" for anyone interested in contributing to snestracker. I intend on GPL'ing the software, incase you were curious about the license

ADSR graph slightly exceeds rect bounds

Screen Shot 2020-06-04 at 2 26 27 PM

As pictured above ever so tiny, the ADSR graph line looks to be jutting out by 1 pixel from the border, meaning that it's a pixel or two too long.

NOTE: I've already fixed it in my tentative commits.

Add option to Count From 0 or 1 in UI

Depends on #50 (checkbox)

Not everyone is a coder and enjoys counting from 0. Maintain the internal implementation but adjust the UI results based on this new setting (or group of settingz)

  • pattern sequencer indices
  • pattern numbers
  • sample indices
    • sample panel
    • instrument editor
  • pattern rows

There is going to be a single discrepancy. Instruments always count from 1, because instrument 0 is the code for no instrument. This could also be adjustable, but let's not go there.

Note / Octave Select GUI assistant

requested by @RowanDDR

When the user double clicks on a note entry in the pattern editor, a piano pops up that helps you visually select the note and octave you want. This piano should or course be limited in range to the snes.

At, the moment, the base note is c-4, highest is c-6, lowest is IIRC c--2 (negative 2) but notes that low aren't well heard, so there is a current 'practical lower bound' of c-0.

The piano should have those lowest octaves printed but greyed out to indicate potential usability in the future.

Keys should highlight themselves on mouse over. They should if possible also cleanly print octave and/or note-name.

Possible licensing woes

I've taken a look at the dependencies, and noticed some licensing worries I wanted to mention to you. Mind you though, IANAL myself.

wla-dx

WLA-DX is afaict licensed as GPL2-only. Unlike jdksmidi which uses the "or later" wording in its source files, WLA-DX doesn't. I'm unsure whether or not a git submodule constitutes as an inclusion of the project into this project's tree, but if it is it'd be a violation of the licensing terms.

A workaround to this might be to remove the submodule and just try to run it from PATH, or relicensing snestracker as GPL2-only.

pcx2snes

This project doesn't seem to have any license at all attached to it. Technically, this makes it pretty much unfree, since it's not your own code. You'd have to seek clarification from the author Neviksti himself on what license his project falls under and somehow make these licensing terms clear in the project itself. Until then including it in your project seems like another licensing violation to me.

A workaround might again be to remove the submodule and just assume it's available in the PATH.

unrar

The inclusion of unrar makes me very worried. It's classified all-around as a non-free and GPL-incompatible project, the fact that you build it, ship it as part of a finished build and seemingly depend on it at runtime sounds like a severe licensing problem to me.

I'd recommend dropping unrar completely and only using 7zDec (also making sure to build 7z without the unrar components). I think detecting the presence of unrar at runtime and calling out to it via the system shell could be okay as well, if cumbersome.

Again though, IANAL.

[st | std] Main Window not fully focused after loading/saving file

Expected Behavior

After loading a file, the main window has full focus

Actual Behavior

After loading a file, the main window is not fully focused. On Mac, this means it will mostly react to user keyboard input but you hear annoying "clang" sound effect for each key press. The user must manually click inside the window to fully focus it.

I believe this issue is present on Windows and Mac, but not on Linux. Need to reconfirm.

Related

This causes a bug in std where if you rip BRR, save, then since the main window is not actually focused, right-clicking anywhere in main window will cause the RIP BRR context menu to appear repeatedly. Once the screen is full focused (by left clicking or alt-tabbing), that problem disappears.

Tracker Wav Export

Selecting "wav export" in the tracker results in an empty wav file. Exporting the .spc from the tracker, and then exporting the .spc as a .wav in the debugger works fine.

MacOS High Sierra 10.13.6

Multi-load BRR

Requested by @RowanDDR

Allow selecting multiple BRR files at once to be loaded sequentially into the sample panel slots.

Should use NFD multi file feature as already used to load multi-spc from debugger.

Should check each slot for pre-existing data, and ask user to preserve or overwrite those slots. This depends on #?? for a dialogue box. (will fill in later)

Move SPD widget into SongSettingsPanel

Here are a couple reasons I want to move the SPD setting off the front page:

  • Tracker SPD setting is an advanced topic; those without tracker background will not need or understand it. The default value is plenty fine.
  • SPD is either set once from the GUI, or multiple times from a pattern effect command. IOW, it's not necessary to have such immediate access to the GUI element not frequently utilized.

The only downside to moving it out is that it cannot be monitored during song playback without the SongSettings Editor panel opened (reducing pattern editor view). But that's not a big deal, because tempo changes on SNES Tracker are first of all not yet supported, 2nd of all will be done by a Tempo Change command (todo), and not by SPD changes (until supported).

Fortunately SPD is already a part of SongSettings class, so just move the render code out of the Main_Window class into the SongSettingsPanel. Of course, that render code actually needs to come out of BpmSpdAddWidget, which has proven to be a bad name for it since it should now be renamed. Maybe call it ConvenientSliders (?). Don't dwell keep it moving.

Also worth noting is the difference between traditional and modern SPD (if I understand it correctly).

Traditional SPD

Without getting into the complications of traditional tracker SPD (how it only reflects the true tempo when SPD = 6 and tempo = 120), I want to highlight a good use of traditional SPD - to affect the tempo of the piece by powers of 2, and (inadvertently) affect effect processing rate, but modern SPD always translates to the same tempo as specified by the tempo setting.

I want to let you know that currently snestracker utilizes a modern SPD setting, to keep a consistency with the tempo specified. If you want to do traditional SPD changes, it will likely be done by a future pattern command to change the song tempo. OR I may introduce an option for traditional SPD. This is for a later time - not a priority atm.

My Thoughts on SPD

One of things I like about traditional SPD is how you can use it to zoom in/out of the rhythmic subdivisions (32nd note, 16th note, eighth note, quarter note, half note, whole, etc) by simply dividing/multiplying the main song speed by powers of 2. The speed command doesn't need to know song tempo to do these zooms, which is cool. However, it does need to know the original SPD. Wouldn't it be cool if there was an effect that didn't need to know any of that? You could just say "Subdivisions Zoomout by X orders" or "SubDivision Zoom In by X orders", and this would basically be a smart tempo command. as long as the pattern could feasably perform the zoom.

Sometimes when doing these "zooms" you'll find you'll need to stretch or squish your pattern data to either make room for the new subdivisions or to make notes stay in line to a previous subdivision. That is another sort of feature request on the way...

"Don't Remind me Again" Dialog Box

Don't Remind me Again Dialog Box

This would be a nice kind of dialog box to have when the user needs to be warned of things that could become annoying on a repeat basis, or for initially helpful messages that are no longer needed. It's the typical "We track your cookies on our website." sort of dialog. A saved internal file would keep track of dialogs not to show again in the future.

Integrate CI bot

I'm interested in dabbling with CI, and this being a cross platform app seems well suited for it. The bot makes sure new code compiles on each platform, and would give me some exp in CI. So, I'm considering MS Azure, Travis, Jenkins, or buildbot.

Min Requirements: easy to get up and running, supports cpp11 on linux, linux / mingw, and osx builds.

I Want to try it on the cloud but I could run it locally if the speed is an issue.

[tracker] Note Playback

Have sound played by the emulator when the user plays notes on a supported input device. This has already been implemented in the debugger midi tab. It can now be converted to the tracker.

  • playback mode : The emulator simply plays sound from the voice that is highlighted by the pattern editor cursor, with the instrument currently selected in the Instrument Panel.
  • record mode : same as playback, but the note gets recorded

Unlike in the debugger instrument tab, It should not be necessary to override the PC (program counter) in tracker mode to create this feature. You'll have to change the way song playback and stopping works to allow the emulator to stay running.

Playback over a chan that's already playing

Of course, if the user is doing playback over a channel during song playback, his input should be highest priority and therefore override any conflicts with the pattern data being played. This would require a set of bitflags in the APU driver (musicianPlayback) which when set, let's the relevant voice know to refrain from actually playing back the current row's data.

Well, maybe in a perfect world this would work. ❄️ On the other hand, I expect that channel will be processing effects parameters and doing wild things to the DSP settings. It's not difficult to imagine wonky sounds happening from this conflict of the voice channel. And sure there are ways around it, but they seem unwise given we're on a 64KB RAM system. It might be a good idea to simply warn the user when they conflict with a channel, that they should migrate to a free voice. This kind of warning should be the kind mentioned in #44

I wouldn't want the voice automatically chosen by software either, but I won't go into why

WatchDog Timer

Consider using a watchdog timer at the following events:

  • song playback has stopped. user-triggered.
  • musician released a piano key

pseudo code

StopEmu:
  SDL_RemoveTimer(emuWatchdog) // remove the old timer (sanity check)
  emuWatchdog = SDL_AddTimer(10000)

NoteON:
  SDL_RemoveTimer(emuWatchdog) // cancel the watchdog

// trigger watchdog timer after the musician releases a piano key
NoteOFF:
  SDL_RemoveTimer(emuWatchdog) // remove the old timer (sanity check)
  emuWatchdog = SDL_AddTimer(10000) // add the new timer

Stay on Track

First support the keyboard commands to play instrument notes. Basically combining the midi instrument tab from Debugger, with the WatchDog (a new member of Tracker), and the PatternEditor module keyboard note event handler.

Edge Cases

  1. Playing a note in playback mode, and holding it while going into recording mode. What do you expect to happen?
  2. Playing a note in playback mode, and starting songplayback while the note is held. In this case song playback start should gracefully cancel all currently playing input notes by fading them out quickly and then starting song. The tracker ignores the note that was held down until it is released and pressed again.
  3. Playing a note during song playback, and then stopping song playback. The note should continue to resonate on its own.
  4. Others?

Other Criteria

Once that's working, go in and attach MIDI input.

Convert tabs to spaces

Some code and header files feature inconsistent tabbing, using a mixture of spaces and raw tabs. This mostly came from my own experimenting.

To a guy who likes to save bytes, raw tabs seem cool, but it can be awkward nailing down how it mixes with spaces to properly format code. I would need to give a clear example but it's just not worth my time.

On the other hand, spaces might force a coder into a certain coding style.

I think the code will be easier to maintain using exclusively spaces when allowed to do so (eg. Not in the Makefile).

This isn't a huge concern; a good modern editor like Sublime can properly display the mixed code uniformly.

So, this issue is Super low priority for anyone who wants to take it up. You may need to find a script or something to identify files that contain lines starting with tabs.

Add copyright to source files

Adding something like the following to all source / header files:

/***************************************************************************
 * camera.cpp  -  class for handling screen camera movement
 *
 * Copyright © 2014 - 2020 Michael Bazzinotti <[email protected]>
 * Copyright © 2020 snestracker contributors
 ***************************************************************************/
/*
   This program is free software; you can redistribute it and/or modify
   it under the terms of the GNU General Public License as published by
   the Free Software Foundation; either version 3 of the License, or
   (at your option) any later version.
   You should have received a copy of the GNU General Public License
   along with this program.  If not, see <http://www.gnu.org/licenses/>.
*/

[sdl] integration testing framework

i'm heavily inspired from my Ruby on Rails learning of Capybara, which simulates the browser experience for UI tests.. here is a relevant snippet

RSpec.feature "Users can create new projects" do
  scenario "with valid attributes" do
    visit '/'

    click_link "New Project"

    fill_in "Name", with: "Sublime Text 3"
    fill_in "Description", with: "A text editor for everyone"
    click_button "Create Project"

    expect(page).to have_content "Project has been created."
  end
end

It would be cool if SDL apps in general could feature similar integration testing. If I have to focus instead more directly on my GUI framework, so be it, but I'd like it to apply to SDL apps as whole.

Well, it's a dream right now, but at least it's documented.

Widget Editor

TL;DR

Use some class definition that gives abstract access to each widget's rect coordinates. The widgets can be repositioned and saved to a gui design file.

In order for the widgets to be able to be repositioned, the code that calculates the positions of the widget's subelements needs to be put into a public function that we can call from the abstract class. The widget must inherit from that class.

Something like this:

class Widget
{
public:
  virtual void setPos(int x, int y);
  SDL_Rect rect;
};

Basically plug that into Meatball's level editor.

Once this design file is initially output, rewrite meatball to load it's gui from it, or an internal default if none present.

This touches on another code design I want to improve which is file formatting. I'm starting to lean towards XML!

Waffle

One of the ugliest things about snestracker in my opinion is the widget positioning and sizing code (view). Through a crazy use of relative positioning, I was able to get the initial layout established.

There's also a direct use of the current font's fixed tile width and height that goes into all of the widget positioning calculations. Not flexible at all!

That being said, I guess widget rendering flexibility with regard to font size is an issue for another day, that will be coupled other related issues (unicode support, ttf fonts - these issues are not yet filed).

Even with the said inflexibility, a gui editor would be neat.

One of my hopes is that efforts here also bare fruit for the level editor in meatball. For example, there is currently no way to select items from a menu. This seems rather meatball-specific though. There must be something, though.. I've got it! An undo buffer! And this undo buffer should also serve to guide the way for The Pattern Editor's undo buffer!

Additional MIDI backends

RtMidi offers some additional MIDI backends that could be enabled with ease in pc/Makefile.

One is a dummy backend that serves as a fallback if no connection to any other compiled-in API endpoint could be established. It is enabled by passing -D__RTMIDI_DUMMY__.

The other is a MIDI endpoint for JACK, a real-time & low-latency daemon for professional audio tasks available on quasi all 3 big platforms. The RtMidi side of it can be enabled with -D__UNIX_JACK__. As the name implies the implementation is intended for Unixoid systems (macOS and Linux), I'm unsure how a Windows system using JACK could be supported.

For the latter, this should be achieved by letting the user decide at build time whether they want ALSA or JACK. Ideally, this would boil down to switching to a proper build system with dependency detection eventually, but for the start detecting an envvar / custom define and adding the required compiler arguments would work well.

Edit: Additionally, an in-app menu to select the preferred backend would be great to have.

Disable non-functional GUI elements

Before, I was comfortable throwing in buttons that did not yet actually do anything yet. But, now that snestracker is receiving its early adopters, these users are questioning why these buttons don't work. heheh.

Here's a thorough checklist of all the buttons that should be greyed out until they have been implemented. They are organized by the Tracker app and Debugger app.

Assume that the following are to be disabled unless marked DELETE.

Debugger

  • Sample Rip context menu: STI. This menu is triggered by right clicking a DIR entry from the DSP tab, or right clicking Blue-colored BRR data in the main window. We want to disable STI for now, because the STI file format has not been defined.

Tracker

Menu

  • File-> Open ST-SPC

  • File-> Export WAV

  • Edit->Copy / Paste

  • Track-> Play / Restart - REMOVE in favor of new UI playback controls (coming soon)

  • Window - REMOVE

Instrument Editor

  • pan
  • F. tune
  • VOL and PAN envelope buttons

Sample Editor

  • Loop
  • F. Tune

Song Settings

Grey out all echo related settings because, although they do function, there is not a way yet to actually enable echo on individual voices.

Instrument Panel

  • Load / Save / Zap buttons

Sample Panel

  • Save
  • Clear

Vague "File Not Found" Error Handling

(As depicted via images at the top of #9)

The easiest fix would be to just add the path string to the error message to be more informative.

The best fix would be to reform the error handling mechanics that respond to errors abroad in the program. First, starting with the mouse cursors asset BMP files. What would be great is to add ability to fail gracefully when certain files somehow go missing that are not essential, such as these optional cursors.

By simply a bit flag or boolean to the relevant data structure, mouse cursor objects can be ignored by the program when their asset files have gone missing.

A Quick Exit sometimes Caused Segfault

Scenario

Exiting the app quickly sometimes led to the following segfault

Expected Behavior

No Segfault

Solution

This problem stems from how on OSX, for unknown reasons, the midi bring-up can be slow. So slow, in fact, that it can take several seconds before the Midi constructor returns. To aid this, a long time ago I had Midi constructed from a thread so that it could take its sweet time while the main app continued being responsive. However, this is the segfault that happens occasionally, and why:

Screen Shot 2020-05-24 at 5 22 42 AM

What was actually happening, was the app was exiting while the Midi constructor was still running from the other thread. 😨

As a remedy, I have added a semaphore to the midithread. The app will close gracefully as always, even during those rare times that the midi engine is still preparing itself. I even added some visual fadeout code (commented out), but it was determined unwanted. Good to know how to impl a fade tho :).

This fix works a charm even on the other OS that didn't exhibit midi bringup issues to begin with (OSX, Linux).

Back & Forward Compatible File Formats

This is high priority because all improvements to file types (project / instrument) are currently discouraging, knowing they will break songs created on an earlier commit.

To remedy this, I have begun strategizing a file format loosely based on RIFF structures and XML-like nesting. Currently a WIP

Song File Format

The goal is to have a fileformat that is back/forward compatible,
easily extendable when new features and components are added.

All integers spanning more than 1 byte are stored little-endian unless
otherwise noted.

The following field starts the file with no ChunkID, but a short non-NULL six-char sequence identifying the file. For a song file, for example

"STSONG"   -- file magic header string. not null terminated

Then each section of data is comprised of a 1-byte ID, an ID-specific length field, followed
by the actual data corresponding to that ID.

1-byte was determined sufficiently large because of the ability to nest IDs. The necessity of a length field was added so that any program can skip ids it doesn't understand.

GlobalID
  Song Title -- null terminated string (Software may impose length limit)
  bpm/spd    -- 16-bit: (BPM << 6) | Spd
                  (0-300)   (1-32?)
                ----BPM---- ==SPD==
                0 0000 0000 0000 00

SongSettingsID
  CoreID:
    mvol       -- 1 byte
    evol       -- 1 byte
    edl        -- 1 byte
    efb        -- 1 byte
    [EXTENDABLE]
  [EXTENDABLE]

SamplesID
  num_samples   -- 1 byte
  What follows is sequential sample data of the follow format:
  SampleID
    CoreID
      index      -- 1 byte
      name       -- null-terminated string (Software may impose length limit)
      brrsize    -- size in bytes of following brr sample
      brrsample
      [EXTENDABLE]
    LOOP_FINETUNE_ID
      TODO: Add rel_loop, finetune settings here
      [EXTENDABLE]
    [EXTENDABLE]
  [EXTENDABLE]

InstrumentsID
  num_instruments -- 1 byte
  What follows are sequential instrument data of the following nature:
  InstrumentID
    CoreID
      index      -- 1 byte
      Name       -- null terminated string (Software may impose length limit)
      vol        -- 1 byte
      pan        -- "
      srcn       -- "
      adsr1      -- "
      adsr2      -- "
      semitone_offset -- "
      finetune   -- "
      [EXTENDABLE]
    [EXTENDABLE]
  [EXTENDABLE]

PatternsID
  num_Patterns  -- 1 byte
  What follows are sequential pattern data of the following format:
  PatternID
    CoreID
      index      -- 1 byte
      len        -- 1 byte: number of rows
      Compressed Pattern Data for 8 tracks
      [EXTENDABLE]
    [EXTENDABLE]
  [EXTENDABLE]

PatSeqID
  Pattern Sequencer Entries -- an arbitrary number of byte sized pattern indices
  that will make up the pattern sequencer. End is signaled by EOF (or $FF)

[EXTENDABLE]

The order of data within an ID, the ID's length field data type, and the datatype of each actual entry must remain fixed. When IDs are extended, they must be extended such that these requirements are satisfied. This way, old versions of the program can read what they can while skipping over unrecognized portions of IDs.

There must be a way to tag new IDs or ID extensions as mandatory, such that they inform older versions of the program that they will not be capable of interacting with this particular file, as it relies on newer features. For this, I propose an optional Compatibility tag.

VersionID
  BuiltBy    -- The version of the program that wrote this file. a 3-byte version string (Maj.Min.Mic)
  Compatible -- the oldest version of the program that can **fully** support this file.  a 3-byte version string as above

Even older programs might be able to load this file, but "the behavior is undefined and possibly unintended by the file's creator." This sort of message should be displayed when loading files that are not fully supported.

Coding Design

Ideally, each data structure corresponding to a specific ID (or set of IDs) would define its own File Loader and add its IDs to a higher level all-encompassing File Loader. I would prefer that this be done statically at compile-time. The higher level File Loader would call the relevant sub-loaders as it parses the file.

Milestone System

NOTE: work-in-progress post.. not fully fleshed out yet

To make 'playing' snestracker more fun, construct a core milestones system. At the heart is persistent record keeping of the user's history. Here are some examples (work in progress).

Can track per session and across lifetime

#times tracking

Samples

  • number of samples loaded
  • number of samples saved
  • number of samples zapped
  • number of times sample editor opened
    • number of times each sample control used

Instruments

  • #times instrument loaded / saved / zapped
  • #times inst panel opened
    • #times each inst control used

to avoid this getting long-winded, let's basically say the #times anything has been done, haha.

length tracking

Pattern Sequencer

  • Amnt time before sequence updated

Pattern Editor

  • amnt time until patterns exhibits user update
  • amnt time user spent in one track
  • amnt time user has stayed in same octave
  • amnt time user has used same instrument
  • amnt time before user inserts 1st effect

Song Settings

  • amnt time before user customizes echo

other

Fun

  • #times an editor panel has been toggled within 3 seconds

These kind of statistics will be referenced by a (hopefully scriptable) event system that will be fronted by the tracker's mascot (tbd), who will behave like Clippy.

Ideally, the system can be constructed in a way that doesn't require 'telling' the other tracker classes that there even is a milestone system. Or, perhaps I need to subclass them and their functions to also post milestones-based metadata or emit signals to a milestones mothership.

when finished

Once this has been layed out in code and operating well:

  • define a scripting syntax in, say, XML (since i'm already planning on using xml for the other formats).
  • implement where those files will be located, and how they load into the milestones system.
  • Design a tutorial scriptable system.

More intuitive ADSR Envelope GUI

The Problem

The current ADSR envelope view is only adjustable by selecting the hardware presets from dropdown boxes. Make this more intuitive.

ADSR Adjustable Graph Points

Although I am electing not to go this way, here are thoughts on how that could be implemented. Adjustable Graph points is something that will need to be eventually implemented for other envelopes, such as Voice Volume, Pan, Noise...

Make the graph itself adjustable. Each point of the envelope would have a semi-large circle that the user can click on to adjust the envelope.

In order to give users a smooth feel of the UI, do not lock the position to the hardware presets, but allow free movement (aside from necessary limits), and then just map their position to the closest hardware value available. I just am not a fan of such loosely coupled control (which is why this is the "almost" solution). Or maybe I just think it would be harder to get this feeling right, easily. That is, if I were to code it.

The Actual Solution

Let's implement UI like a traditional Synthesizer - KNOBS! This grants the best of both worlds. It makes it smoother and faster to adjust the parameters, and it's easy to stay "locked in" with the available hardware presets in a clear and simple manner. So we'll have 4 knobs and you click and drag to cycle across the preset values. I also think knobs contribute to the overall musician's feel of music software.

As you turn the knob, the graph responds accordingly, and a text of the parameter value should float above your cursor as you have the mouse button down.

Since the decay cannot be adjusted when the sustain level is maxed out, grey out and disable that control during such a condition.

Of course, there is currently no Knob class, so that will have to be created. and a special sub-class PresetKnob or something that accepts a list of preset values for the knob.

Tooltips

Appropriate GUI elements should have a tooltip that is displayed after the user has hovered over the element for a certain amount of time.

The tooltip should provide a brief description of the element, along with the keyboard shortcut associated with this element (available after #28 has been accomplished).

Once the tooltip has become active, it should remain so until the mouse is moved outside of the element's bounding box.

Tooltips may be disabled from the Options menu

[std] ability to select SRCN from inst tab

When demoing my workflow, I came across a time when this would have been useful. A single voice was using 3 different SRCN rapidly. It was harder to stop the music when the desired SRCN was selected by a voice.

Although there are alternative solutions, such as slowing the tempo down and stopping the music when desired SRCN is being used, I think this might be a nice touch.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.