Hello all
This project was my thesis project, and it's been much while since I dealt with it. 8 years ! :)
Regarding the rising era of the game technologies, I decided to have a look at the project because of some coincidences that I faced this week (06.08.2022).
I have added required dependencies and some documentation telling how you can run this project with your PD patches and get some dsp code written for Faust.
If you have any questions, please fire an Issue.
Mephisto is a transpiler for converting sound patches designed using the graphical computer music environment Pure Data to the functional DSP programming language Faust. Faust itself compiles into highly-optimized C++ code. The aim of the transpiler is to enable creating highly optimized C++ code embeddable in games or other interactive media for sound designers, musicians and sound engineers using PureData in their workflows and to reduce the prototype-to-product delay.
PD and Max/MSP softwares are widely used for procedural sound design for games. However, the software cannot be easily integrated with games. On the other hand, various optimized synthesizes can be developed using low level languages by Faust. Transporting models and applying the same algorithms from PD to Faust is really a burden to procedural sound designers. The aim of this project is to write a source to source transpiler which transpiles PD source to Faust source. After getting faust code, it is up to you and Faust to generate the C++ code.
- Build the application from its sources
javac -cp antlr-4.2.2-complete.jar:. -d bin src/*.java
- For testing purposes you can use the input1.pd file to see whether the app is running correctly or not
java -cp antlr-4.2.2-complete.jar:./bin ConvertPd input1.pd
- You will see the transpiled output in the output console. Additionally,
input1.dsp
file will be created in order to be used in Faust. My using this file with Faust, you can get optimized C++ code which can be used natively in your games.
- Open your IDE, then clone and open the project.
- Right click the file
antlr-4.2.2-complete.jar
and clickAdd as a library
. - Right click
src/ConvertPd.java
file, then go toMore Run/Debug
>Modify Run Configuration
- For testing purposes, give the
input1.pd
file as program argument and then clickOk
- Finally, right click again the
src/ConvertPd.java
file, then clickRun ConvertPD.main()
- You will see the transpiled output in the output console. Additionally,
input1.dsp
file will be created in order to be used in Faust. My using this file with Faust, you can get optimized C++ code which can be used natively in your games.
Rows.g4
file defines the grammar of internals of the .pd files. After you draw a patch and save it in PureData (PD), you will see a bunch of lines defining what you have drawn in the UI when you open the file with a text editor.- All files contained in the expression
Rows*.java
are created by ANTLR (https://www.antlr.org/) usingRows.g4
file. ConvertPdListener.java
is the file where the whole logic resides. Compiling and Faust code generation happen in here by using the Lexer and the Parser which are generated by ANTLR.ConvertPd.java
file is the main class which runs the application by using the classes created via ANTLR and the fileConvertPdListener.java
If you want to further improve the transpiler, there are two things to consider:
- You can extend the grammar by editing the
Rows.g4
file. You can add new rules for the grammar if you want to implement some unimplemented blocks of PD. After editing the grammar file, you should re-build the project as instructed above. - After re-building the Lexer and Parser, you should add the transpiling logic of the block into the
ConvertPdListener.java
file.
This file's structure is as below:
public void enterRow(RowsParser.RowContext ctx)
function is called for every row in the .pd file. In this function,PDObject
(class)s are created by looking the tokens provided by theParser
.- Everything is started when the exitFile function is called. This is because
~dac
object in the pd file resides at the bottom of the file. If you think the pd patch as a graph and the~dac
object as the starting point, this function starts the traversal. It looks for the objects coming into the inlets of the~dac
object and then callspublic String createObject_setOutput(int objectNumber,int outletNumber)
function. createObject_setOutput
function is used for every otherPDObject
and defines the Faust equivalents of the objects. Additionally, it is responsible for connecting the inlets and the outlets of the objects. This function continues to be called recursively until a leaf object is reached. As a result whole graph is traversed and the Faust code is generated.