Quote:
Originally Posted by John Allsup
What I am interested in is programmatically creating and manipulating RPP files. As such, it would be nice to have a simple python module for doing this with scripts. I have written basic .lua plugins for doing some things, but many things seem not to work from reascript.
|
Wondering if you got anywhere? Anyway here's some help if you need it..
It is pretty easy to parse and manipulate RPPs.
There are a few quirks but not many i.e. RECCFG, COMMENT, VST, AU, JS, NOTES tags all contain data chunks, rather than typical attribute lines.
I parse and alter RPPs for the reconform function in Vordio. The parser is only about 50 lines of pretty basic code. That turns the RPP into a node based object model, which I can then alter, and write out the object model again as a new RPP after.
http://vordio.net/reconform
Here are some basic rules..
tag = line that starts with <
dataline = line that is inside one of a few special tag types. Just store these lines as part of tag data.
attribute = line that does not start with < and is not a dataline.
For both tags and attributes the rest of the tokens on same line are the parameters for that tag/attribute.
The tokenizer simply breaks down a line into words (while accounting for reaper escaped strings in the process as they may have spaces and quotes in). There is no point breaking down datalines. Just keep them and regurgitate them later.
You need to make sure order is preserved as some attributes are sensitive to where they appear i.e. SOFFS (source offset) after a TAKE attribute relates to that take.
I do this by making Tag and Attribute extend Basic node. RPPTag extends RPPNode (can have children), RRPAttribute extends RPPNode (doesn't have children). But they both can have extra parameter words after them on same line.
Also although Reaper indents it's files, it doesn't care if you don't when you write out an RPP.
Code:
void parse() throws IOException {
String line;
while ((line = reader.readLine()) != null) {
line = line.trim();
if (line.startsWith("<")) {
openTag(line.substring(1));
} else if (line.startsWith(">")) {
closeTag();
} else if (tag.isDataTag()) {
// some tags contain arbitrary binary data lines
parseData(line);
} else {
// Normal attribute line
parseAttribute(line);
}
}
}
void openTag(String line) {
tag = new RPPTag(tag, null);
if (root == null) {
root = tag; // first tag found - must be root
}
RPPTokenizer tok = new RPPTokenizer(line);
String name = tok.next();
tag.setName(name);
tag.setParams(parseParams(tok));
}
Code:
public class RPPTokenizer {
private String line;
private int index;
private StringBuffer buff;
public RPPTokenizer(String line) {
this.line = line;
this.index = 0;
this.buff = new StringBuffer(256);
}
public boolean hasNext() {
return index < line.length();
}
public String next() {
buff.delete(0, buff.length());
// ignore white space
while (index < line.length()) {
char c = line.charAt(index);
if (!Character.isWhitespace(c)) {
break;
}
index++;
}
// Is next character a quote?
char c = line.charAt(index);
boolean quote = false;
int quoteChar = 0;
if (c == '\'' || c == '"' || c == '`') {
quote = true;
quoteChar = c;
} else {
buff.append(c);
}
index++;
// read till quote or whitespace
while (index < line.length()) {
c = line.charAt(index++);
if (quote) {
if (c == quoteChar) {
break;
} else {
buff.append(c);
}
} else {
if (Character.isWhitespace(c)) {
break;
} else {
buff.append(c);
}
}
}
return buff.toString();
}
}