An idea for instruments

This is an archive of a topic from NESdev BBS, taken in mid-October 2019 before a server upgrade.
View original topic
An idea for instruments
by on (#212677)
Right at the moment, ggsound allows 256 byte long volume envelopes, pitch envelopes, duty envelopes and arpeggios. For each playing note, an address for each envelope must be loaded into zp and then the envelope executes.

That seems kind of extreme. I wonder how common it would be to take advantage of such potentially long sequences?

If I allowed each to occupy a single 256 byte sequence could just have "instruments" where each of these type of sequences start at different points, and then I'd only have to load the address for the current instrument once. The only types of sequences which are usually long are volume and pitch. From what I've seen and used myself, arpeggios and duty are typically very very short. In fact I've never actually seen a looping duty envelope or used one, I typically just have a max of 2 values where the first creates a crisp "attack" sound.
Re: An idea for instruments
by on (#212680)
I recently used some pretty long pitch envelopes to compensate for FT2 (according to the readme) not being able to accumulate pitch changes across loops. Even so i didn’t come near 256 bytes for an envelope. The longer it goes on, the less likely it is you’re going to hear it, + in the case of ft2 you can retrig the phrase with a new note or instrument change.
Re: An idea for instruments
by on (#212681)
FrankenGraphics wrote:
I recently used some pretty long pitch envelopes to compensate for FT2 (according to the readme) not being able to accumulate pitch changes across loops. Even so i didn’t come near 256 bytes for an envelope. The longer it goes on, the less likely it is you’re going to hear it, + in the case of ft2 you can retrig the phrase with a new note or instrument change.

I think ggsound is able to accumulate pitch changes, it uses relative pitch adjustment. How long was your longest envelope? I'm thinking of making the above described change; it may make ggsound approach famitone's speed (but bring along other advantages 8-) )
Re: An idea for instruments
by on (#212683)
62 pitch entries long. I had two like that.

Else it is mostly none or 1-5 entries

with relative pitch loops, most would either be just 1, or maybe in the range of 8-12 for a vibrato. though... dang it, a vibrato ought to work like this because it doesn't need relative pitch adjustment across loops? Good this was brought to light haha

Mostly, relative pitch adjustment is for glissandos. Saves you both envelope entries and interim note entries, and also saves you from pain.
Re: An idea for instruments
by on (#212685)
GradualGames wrote:
Right at the moment, ggsound allows 256 byte long volume envelopes, pitch envelopes, duty envelopes and arpeggios. For each playing note, an address for each envelope must be loaded into zp and then the envelope executes.

That seems kind of extreme. I wonder how common it would be to take advantage of such potentially long sequences?

Someone converting a recorded loop played on live drums to noise, using a tool such as lidnariq's, might end up using long sequences.

GradualGames wrote:
If I allowed each to occupy a single 256 byte sequence

If all envelopes in the set have the same loop length, you can interleave them and see if that shrinks your RAM requirement.

GradualGames wrote:
In fact I've never actually seen a looping duty envelope or used one, I typically just have a max of 2 values where the first creates a crisp "attack" sound.

Looping 0 1 duty in noise creates a cymbal sound. Looping duty in pulse creates the PWM sound of the pulse part in the Skate or Die 2 intro or my "Katyusha" cover.
Re: An idea for instruments
by on (#212686)
tepples wrote:
GradualGames wrote:
If I allowed each to occupy a single 256 byte sequence

If all envelopes in the set have the same loop length, you can interleave them and see if that shrinks your RAM requirement.

What do you mean about loop length being the same?
What I'm thinking of doing is defining instruments like this:
instrument0:
.byte <vol_offset>,<pitch_offset>,<duty_offset>, <actual volume bytes>, <loop or stop opcode>, [optional loop point], <actual pitch bytes>, <loop or stop opcode>, [optional loop point], <actual duty bytes>, <loop or stop opcode>, [optional loop point], <actual arpeggio bytes>, <loop or stop opcode>, [optional loop point]

With this definition, I'll just be loading a 16 bit instrument address ONCE per channel, rather than loading a 16 bit address for EACH of the four envelope types. My hope is since the engine spends most of its time updating sequences that this could save a couple hundred cycles per frame. The constraint would be that all envelopes in use by any given instrument must all fit together in one 256 byte sequence. In actual practice, it seems like this should work. Really really long instruments that aren't long due to a loop point are pretty rare I think. Any extreme situations where it does need to be longer could just play a new note that starts where the last envelope leaves off...
Re: An idea for instruments
by on (#212696)
GradualGames wrote:
tepples wrote:
If all envelopes in the set have the same loop length, you can interleave them and see if that shrinks your RAM requirement.

What do you mean about loop length being the same?
What I'm thinking of doing is defining instruments like this:
instrument0:
.byte <vol_offset>,<pitch_offset>,<duty_offset>, <actual volume bytes>, <loop or stop opcode>, [optional loop point], <actual pitch bytes>, <loop or stop opcode>, [optional loop point], <actual duty bytes>, <loop or stop opcode>, [optional loop point], <actual arpeggio bytes>, <loop or stop opcode>, [optional loop point]

I was thinking this:
Code:
instrument0:
.byte <duty|volume>,<pitch_offset>
.byte <duty|volume>,<pitch_offset>
.byte <duty|volume>,<pitch_offset>
.byte <duty|volume>,<pitch_offset>
.byte <loop or stop opcode>

It still loads the 16-bit address only once, but all loops need to be the same length.
Re: An idea for instruments
by on (#212700)
tepples wrote:
I was thinking this:
Code:
instrument0:
.byte <duty|volume>,<pitch_offset>
.byte <duty|volume>,<pitch_offset>
.byte <duty|volume>,<pitch_offset>
.byte <duty|volume>,<pitch_offset>
.byte <loop or stop opcode>

It still loads the 16-bit address only once, but all loops need to be the same length.

Is this done in any engines you know of out of curiosity? That sounds kind of constricting to me, thinking as a FamiTracker user (wanting to just design whatever envelope is appropriate for my instrument without worrying all that much about constraints of the driver which will be in use)
Re: An idea for instruments
by on (#212703)
GradualGames wrote:
tepples wrote:
I was thinking this:
Code:
instrument0:
.byte <duty|volume>,<pitch_offset>
.byte <duty|volume>,<pitch_offset>
.byte <duty|volume>,<pitch_offset>
.byte <duty|volume>,<pitch_offset>
.byte <loop or stop opcode>

It still loads the 16-bit address only once, but all loops need to be the same length.

Is this done in any engines you know of out of curiosity?

Pently does essentially this. The pitch offset is in semitones, making it technically an arpeggio envelope.
Re: An idea for instruments
by on (#212704)
FrankenGraphics wrote:
62 pitch entries long. I had two like that.

Else it is mostly none or 1-5 entries

with relative pitch loops, most would either be just 1, or maybe in the range of 8-12 for a vibrato. though... dang it, a vibrato ought to work like this because it doesn't need relative pitch adjustment across loops? Good this was brought to light haha

Mostly, relative pitch adjustment is for glissandos. Saves you both envelope entries and interim note entries, and also saves you from pain.

If you need relative pitch, ggsound supports that as I think it is the default behavior of famitracker pitch envelopes. I have not tried a loop point with anything other than a vibrato, but as it is all relative values, I know it should accumulate in one direction if that is what you want.

Also 62 byte envelopes (for volume and pitch) would easily fit in this new approach I'm thinking of doing. Thanks for the feedback.
Re: An idea for instruments
by on (#212706)
tepples wrote:
GradualGames wrote:
tepples wrote:
I was thinking this:
Code:
instrument0:
.byte <duty|volume>,<pitch_offset>
.byte <duty|volume>,<pitch_offset>
.byte <duty|volume>,<pitch_offset>
.byte <duty|volume>,<pitch_offset>
.byte <loop or stop opcode>

It still loads the 16-bit address only once, but all loops need to be the same length.

Is this done in any engines you know of out of curiosity?

Pently does essentially this. The pitch offset is in semitones, making it technically an arpeggio envelope.

That's interesting, sounds like vibratos would have a rough, stepped quality in that case not being able to fine tune the depth of the vibrato to smaller than a semitone? (just curious about this)
Re: An idea for instruments
by on (#212708)
Quote:
If you need relative pitch, ggsound supports that as I think it is the default behavior of famitracker pitch envelopes. I have not tried a loop point with anything other than a vibrato, but as it is all relative values, I know it should accumulate in one direction if that is what you want.

Also 62 byte envelopes (for volume and pitch) would easily fit in this new approach I'm thinking of doing. Thanks for the feedback.




Thanks for clarifying that. :) I'll be sure to check that out sometime soon, maybe for the next project. For the compo, i think we're a little too late to be swapping drivers haha!

Yeah, basically you can substitute all gliss/portamento effects (1xx, 2xx, 3xx, Rxy and Qxy) with looped single entry pitch envelopes in most cases as long as they accumulate across the loop seam. Might need a couple of dedicated instruments per "sound" to be doing in an agile fashion, but still. two or three entries gives you even more precise control of the rate, and it's a trivial addition.
Re: An idea for instruments
by on (#212709)
Vibrato in Pently is an effect applied separately. It's roughly equivalent to 400 at note start then 451, 453, 455, or 457 twelve ticks later.

If you want both pitch and arp, I guess you could use bits 5 and 4 of the duty/volume byte.