Posts

Showing posts with the label PurrFX

PurrFX project final thoughts

Well, we can assume that the project is finished. Although, of course, it can be refined endlessly, I completely fulfilled the original plan. You can use the framework to create your own music program (tracker or even something like DAW), you can create utilities to work with NSF files. You can also add on-the-fly music generation support to your retro game using the framework. Or, simply study the internal structure of the emulation code by collecting logs and studying the source code. I really hope that all this is useful to someone, because I have spent probably hundreds of hours of my life on studying and experimenting. I was really trying to make the framework easy to use, so why not give it a try? If anyone needs to improve it, just let me know. For example: Enabling / disabling sound channels Playback speed control Panning Support for FME-7 and VRC6 chips Adding support for some other emulation code And finally, some statistics: Duration of work is 43 days (August 10 through Sep...

PurrFX project update 20

Project status overview as of September 21, 2020. Commits : September 21, 2020. In this update, I've added features to go the other way. I.e. from the piano key number, get the corresponding registers for the Pulse1 , Pulse2 and Triangle channels. The Piano demo project shows you exactly how to use these features. At this stage, the capabilities of the framework should be enough to create music programs of very high complexity.   Project pages: https://github.com/TheCatNose/PurrFX https://github.com/TheCatNose/PurrFX-sample-projects    

PurrFX project update 19

Image
Project status overview as of September 20, 2020. Commits : September 20, 2020. Development has gone far enough and it's time for some really interesting updates! Let's start with the fact that the library now has classes and functions for converting register values ​​to sound frequencies. For example, for the Pulse1 channel, registers $4002 and $4003 are responsible for the sound frequency. Their combination gives us an 11-bit value, which, according to a special formula, is converted into a reproducible sound frequency. Also, the library (using the CNote class) allows you to convert the frequency of a sound to a note, i.e. into a specific piano key. You can use this feature to render notes in one way or another (for example, on a piano roll). The CNesState class allows you to do something like the simplest emulation of the processor's work, accumulating the values ​​of the registers. Thus, it is possible to simulate playback of track data even without using CNes cla...

PurrFX project update 18

Image
Project status overview as of September 16, 2020. Commits : From September 13 through 16 of 2020. One feature was very needed. It was not possible to edit individual register data fields in an easy way. It is these fields (groups of bits) that are responsible for such sound parameters as duty, volume, pitch and others (depending on the sound channel). For register field names you can visit this page: https://wiki.nesdev.com/w/index.php/APU CRegister class is now available, which organizes universal access to register fields. If you wish, you can make something of your own, more convenient, based on this class. For example: New demo project HackPlayer shows how you can actually use the CRegister class to change the duty for the Pulse1 and Pulse2 channels as needed.   Related information: https://wiki.nesdev.com/w/index.php/APU   Project pages: https://github.com/TheCatNose/PurrFX https://github.com/TheCatNose/PurrFX-sample-projects

PurrFX project update 17

Project status overview as of September 12, 2020. Commits : From September 9 through 12 of 2020. Over the past few days, I have done a lot of work on the PurrFX framework. Fixed bugs, did some refactoring. But the most important thing is that now you can use WAV files as audio samples. The code supports mono and stereo modes, 8 bit and 16 bit modes and a typical set of sampling rates. In addition, you can export audio samples from NSF files to WAV files. A new test project called DrumMachine can serve as the basis for your tracker or other interesting program!   Related information: https://en.wikipedia.org/wiki/WAV https://en.wikipedia.org/wiki/Pulse-code_modulation   https://en.wikipedia.org/wiki/Differential_pulse-code_modulation   Project pages: https://github.com/TheCatNose/PurrFX https://github.com/TheCatNose/PurrFX-sample-projects    

PurrFX project update 16

Image
Project status overview as of September 8, 2020. Commits : September 8, 2020. This update is dedicated to one single demo project ( ProceduralAudio ). It's not hard to guess what exactly is going on there. So what is needed for procedural sound generation with PurrFX? This is very simple. You just need to create an emulator object and attach your CFrameDataProducer implementation to it. The basic amount of code looks like this:   And for the generator, you need to define a function that returns CFrameData object upon request.   This is how you can harness the power of the NES emulated sound system with some really simple code!      Project pages: https://github.com/TheCatNose/PurrFX https://github.com/TheCatNose/PurrFX-sample-projects  

PurrFX project update 15

Project status overview as of September 7, 2020. Commits : From September 6 through 7 of 2020. Over the past two days, I have done quite a lot. And the number of commits in the PurrFX repository has already exceeded 200! I started by fixing the problem of multi-threaded access to the emulation code in the NsfPlayer project (SDL version). I just used a mutex. Also for this project, I added the ability for the user to enter the name of the file to open. After that, I added classes to the library that allow you to store in memory data loaded from NSF files. These are the CDpcmDataBuffer and CFrameDataBuffer classes.   Then I created a pretty funny project called ReversePlayer . This project loads data from NSF files, stores it in memory (using the classes mentioned above) and ... Plays it backwards! Moreover, this is not just reverse sound, but the execution of commands in the reverse order. For this, a special proxy class CFrameDataProxy is used.   Looking at this project, on...

PurrFX project update 14

Image
Project status overview as of September 5, 2020. Commits : From September 3 through 5 of 2020. I've made a new repository for sample projects using the PurrFX library! At the moment there is only one “NsfPlayer” project (in two versions - Qt and SDL2). This is the simplest possible use case. So ... Let's measure the amount of code (I mean interacting with the PurrFX library) that is needed to write such a program: Hmm ... Not so much, really!     Related information: https://en.wikipedia.org/wiki/Qt_(software) https://en.wikipedia.org/wiki/Simple_DirectMedia_Layer   Project pages: https://github.com/TheCatNose/PurrFX https://github.com/TheCatNose/PurrFX-sample-projects

PurrFX project update 13

Project status overview as of September 1, 2020. Commits : August 31 through September 1, 2020. The latest library update is aimed at improving cross-platform compilability. For example, when using the library on Windows, so-called wide chars (wchar_t) are used for file paths. Also, I've tried compiling and running a test project on linux with the g++ 9 compiler. Based on this experience, the library was modified accordingly. Project page: https://github.com/TheCatNose/PurrFX

PurrFX project update 12

Project status overview as of August 30, 2020. Commits : August 30, 2020. Last time I added the ability to extract DPCM audio samples from NSF files. This was done for practice and to expand the capabilities of the PurrFX library. Plus, it's great to be able to use sounds from your favorite games!   This time, as you might guess, I added support for using DPCM audio samples. But I wanted to do this in accordance with the requirements of modernity, i.e. I wanted to provide the ability to use an unlimited number of samples. Since the original hardware does not provide such possibilities, I had to do tricks again. The trick is to use one single memory segment for all samples and write specific samples there as needed, i.e. upon request. Two types of access are supported - “classic” and “modern”. In the “classic” access mode, the sample identifier is a combination of sample address and sample size. And thanks to this mode of operation, it is possible to play frame data obtained from an...

PurrFX project update 11

Image
Project status overview as of August 28, 2020. Commits : August 28, 2020. In today's small update, I added an important feature - support for exporting audio samples in RAW format. Samples exported in this format can be opened for editing by the audacity . Many other programs should also have this capability.   Here's how to do it: 1. Start audacity; 2. Select the menu item File ➝ Import ➝ Raw Data; 3. Select the RAW file; 4. Specify the following import options: Done! The sample can be listened to and edited. In this case, the sound will be slightly different from what the emulator produces, and the reason for this is the mismatch in the playback speed. To implement export to RAW format, it was necessary to understand how an audio sample works in its original form. It (1-bit delta-encoded sample) should be considered as a sequence of bits, i.e. something like this: 1100101110101111000100001... The initial signal level is taken to be zero and with each new bit we increase or de...

PurrFX project update 10

Project status overview as of August 27, 2020. Commits : August 27, 2020. One of the interesting features of the NES is its distinctive sounding audio samples. Their support is sorely lacking in the PurrFX library. It's the right time to do it! The first step, of course, is to implement support for extracting samples from NSF files.   The method I use is most likely not entirely conventional. But I decided not to bother and just let the emulator do its job. All we need is to track the start of DPCM sample playback (writing to the registers $4012, $4013, $4015) and read the data from memory using special function. And then save the collected data to a file. Related information: https://wiki.nesdev.com/w/index.php/APU_DMC Project page: https://github.com/TheCatNose/PurrFX

PurrFX project update 9

Image
Project status overview as of August 26, 2020. Commits : August 26, 2020. It is necessary to make sure that no existing NSF file is required to generate sound. So I made a simple but sufficient ready-to-use NSF file stored right inside the PurrFX library. Remember the 4th update in which we made NSF files in the HEX editor? It was exercise for what we did today.   In fact, the PurrFX framework is ready for organizing an audio stream based on any desired set of input data. This is very simple: 1. The audio library requires a portion of the sound and refers to your program; 2. Your program refers to one of the implementations of CNes (for example CNesGme ); 3. CNesGme starts the emulation process and, as necessary, refers to CFrameDataProducer implementations (for example CFrameDataFileReader ).   This process can be represented in the form of this diagram:   There are still lack of high-level classes to create the required set of frame data, but nevertheless the scheme...

PurrFX project update 8

Image
Project status overview as of August 25, 2020. Commits : August 25, 2020. After collecting the data, the next logical step is to use it. To do this, I created a class that reads frame data from a file and prepares it for use. This class, like any other implementation of CFrameDataProducer , interacts with the emulation code object by attaching to it.   What happens inside the emulation code for playing frame data based sound resembles (as I think) the operation of a device called the “Game Genie”. As soon as it comes to the play function from the NSF file, the code is intercepted and redirected to the play function at $6000 address. I cannot say that it is beautiful, but most likely there simply does not exist a more suitable way to use an arbitrary set of audio related instructions (in any required quantity, even in gigabytes). This is what the log file looks like, demonstrating the operation of the play function at the $6000 address:   And here is how it sounds (using the da...

PurrFX project update 7

Image
Project status overview as of August 24, 2020. Commits : August 24, 2020. You need some source data to generate sound. In our case, the data is the bytes written to the registers. Where to get such data? You can create it yourself. But it's much easier (especially for a start) to use existing data. Obviously, NSF files are the most suitable data source. The collected data is grouped by frames. Sometimes (very often) there are several writes to the same register per frame. In this case, we use the last of the entries. Please don't ask me why this works so fine - I don't really understand myself. I invented this method after many hours of experimentation. Similar attachment technique used for audio logging and exporting. Just attach data collector class instance to the emulator object (you can just use the ready-made one) and that's it! And this is how the simplest data collection code looks like: Project page: https://github.com/TheCatNose/PurrFX  

PurrFX project update 6

Project status overview as of August 23, 2020. Commits : From August 22 through 23 of 2020. This time, I've updated different audio formats support (two bit depth modes and mono/stereo mode). Making the necessary changes directly to the “Game Music Emu” library is not an easy task. Therefore, I added a special proxy buffer to PurrFX that allows you to do audio conversion on the fly. This should not affect the quality in any significant way. And the sound parameters are now defined by a special CAudioFormat class. Related information: https://en.wikipedia.org/wiki/Sampling_(signal_processing)#Sampling_rate https://en.wikipedia.org/wiki/Audio_bit_depth https://en.wikipedia.org/wiki/Stereophonic_sound   Project page: https://github.com/TheCatNose/PurrFX

PurrFX project update 5

Image
Project status overview as of August 21, 2020. Commits : From August 20 through 21 of 2020. Latest code changes have not brought anything fundamentally new. Rather, they are aimed at making the library more convenient. There are some minor tweaks that are needed for future additions of functionality though. As a demonstration, I want to show what the simplest example of using the PurrFX library, which converts an NSF track to a WAV file: Of course, the code will be larger with includes and error checking, but nonetheless. Project page: https://github.com/TheCatNose/PurrFX

PurrFX project update 4

Image
Project status overview as of August 18, 2020. Commits : August 18, 2020. The library requires an NSF file to generate audio data. So, we need to get experience in creating such a file. We will use the convenient HEX-editor HxD for this: https://mh-nexus.de/en/downloads.php?product=HxD20 Let's try to make the simplest NSF according to the documentation, step by step: https://wiki.nesdev.com /w/index.php/NSF Look at the description of NSF file structure:   So let's get started! “NESM”, 0x1A and version number. Everything is simple so far:   Let's go further. The number of tracks and the number of starting track. In our case it is 1 and 1: Let's go further. Load address, initialization address, play address. I assume the first two addresses may be the same. Following documentation we can use $8000 address, so let it be 0x8000 and 0x8000. The initialization function will contain only one command (exit from the function). This means that the following address is $8001 so ...

PurrFX project update 3

Project status overview as of August 17, 2020. Commits : From August 16 through 17 of 2020. Logging should provide useful information. This is exactly what the latest changes in the PurrFX library were aimed at. It was necessary to see at least some structure of the code. And the most important information was also needed... Obviously I'm talking about changes in the APU registers that control the sound. New elements of the log: 1. Main functions (“init" and "play"); 2. Switching to a new frame; 3. Writing to the APU registers. It was pretty easy to make all the necessary modifications of the "Game Music Emu" library with previously acquired experience.   Related information: http://www.cplusplus.com/forum/lounge/119813/1/ https://wiki.nesdev.com/w/index.php/APU#Registers Project page: https://github.com/TheCatNose/PurrFX

PurrFX project update 2

Project status overview as of August 15, 2020. Commits : From August 14 through 15 of 2020. Alright, things are getting serious... To understand the principles of the "Game Music Emu" library (and any other code btw), you have to experiment a lot. You have to debug it, try to change something, read documentation. In the course of such experiments, I managed to find a place where the Ricoh 2a03 processor emulator executes machine instructions. Did you know about it? Processing NSF files is not that easy. Then I added basic logging to the capabilities of PurrFX. At this moment it supports logging of executed machine code only. As an experiment, I’ve collected a log of work for something simple: “Super Mario Bros.nsf” (the very famous first track)...Wow! The output file size is almost 9 MB and it contains 469306 lines (each line is one machine instruction) for just one minute of music. This means the NES processor actually does a hell of a lot of work, and the console itself is ...