-
ddw_music
@nicnut said:
But I just had a revelation that I can't believe I never though of before. If I multiply the output of line~ by a number I can separate pitch and time.
Ah ok, so what you meant is to separate pitch and the duration of playback -- sometimes use only part of the buffer.
Another solution (I'd say a more standard solution) is to use the phasor~ or line~ to handle pitch and playback start (I still think line~ is easier for your use case here), and use an envelope to choke the audio after the desired duration. Then it doesn't matter if the playback index keeps moving -- when the envelope closes, the sound is over.
One of my "audio engineering 101" bullet points is: every sound in nature has an envelope, so your patch should use an envelope too.
hjh
-
ddw_music
@nicnut said:
There is a number box labeled "transpose." The first step is to put a value in there, 1 being the original pitch, .5 is an octave down, 2 is an octave up, etc.
Here, you'd need to calculate the phasor frequency corresponding to normal playback speed, which is 1 / dur, where dur is the soundfile duration in seconds. Soundfile duration = soundfile size in samples / soundfile sample rate, so the phasor~ frequency can be expressed as soundfile sample rate / soundfile size in samples. Then you multiply this by a transpose factor, ok.
But I don't see you accounting for the soundfile's size or sample rate, so you have no guarantee of actually hitting normal playback speed.
After that you can change the frequency of the phasor in the other number box labled "change phasor frequency without changing pitch."
If you change the phasor frequency here, you will also change the transposition.
This way, I can make the phasor frequency, say .5 and the transposition 2,
Making the eventual playback speed 1 (assuming it was 1 to begin with), undoing the transposition.
which I don't think I can do using line~ with tabread4~.
The bad news is, you can't do this with phasor either.
hjh
-
ddw_music
@nicnut said:
If I pick the transposition first, then choose the phasor~ frequency second I can separate the pitch and the time
What do you mean by "separate the pitch and the time"? (Asking because often, computer-logic problems become easier after stating the problem in a more precise way.)
hjh
-
ddw_music
@nicnut said:
Yes line~ would be better, but one thing I am doing is also playing the file for longer periods of time, by lowering the phaser~ frequency, and doing some math the transpose the pitch of the playback that I would like to keep. With line~ I don't know how to separate the pitch and the playback speed.
If I understand you right, separating pitch and playback speed would require pitch shifting...?
With phasor~, you can play the audio faster or slower, and the pitch will be higher or lower accordingly.
With line~, you can play the audio faster or slower, with the same result.
To take a concrete example -- if you want to play 0-10 seconds in the audio file, you'd use a phasor~ frequency of 0.1 and map the phasor's 0-1 range onto 0 .. (samplerate*10) samples. If instead, the phasor~ frequency were 0.05, then it would play 10 seconds of audio within 20 seconds = half speed, one octave down.
With line~, if you send it messages "0, $1 10000" where $1 = samplerate*10, then it would play the same 10 seconds' worth of audio, in 10 seconds.
To change the rate, you'd only need to change the amount of time: 10000 / 0.5 (half speed) = 20000. 10 seconds of audio, over 20 seconds -- exactly the same as the phasor~ 0.05 result.
frequency = 1 / time, time = 1 / frequency. Whatever you multiply phasor~ frequency by, just divide line~ time by the same amount.
(line~ doesn't support changing rate in the middle though. There's another possible trick for that but perhaps not simpler than phasor~.)
hjh
-
ddw_music
If the goal is to play it one-shot and then stop, wouldn't line~ be better?
hjh
-
ddw_music
@jbaker said:
Success!
A-ha! Fantastic
I had a feeling you were just that close -- happy that you got it working.
hjh
-
ddw_music
I'd like to make a suggestion: Pick one set of objects to handle OSC, and just use those. It's in the nature of a tech forum for different people to have different opinions and offer multiple suggestions, but mixing and matching many different approaches can also lead to confusion.
So, for example, your screenshot -- at the top left, you have [packOSCstream] (why this and not [packOSC]? ** ) and then below, [oscformat]. That's a source of confusion. These two objects have quite different ways of handling OSC addresses (or what I've been calling "command paths") -- two idioms. Nah, this is a good way to introduce mistakes. So, pick one that you're more comfortable with.
** Ah, I see, [packOSC} help says "[packOSCstream] is a way to send OSC over TCP or serial connections" -- but you're using UDP, so, not relevant. Again, simplify: [packOSC] or [oscformat], pick one and stick with it.
Also -- you've got elements of this patch where it's already been explained why they are incorrect. If you connect a "send..." message box directly to a [netsend -u -b], it will not send an OSC-formatted message. Since you are sending to devices that expect OSC-formatted messages, for OSC it is always incorrect to pass a "send..." message directly to [netsend]. Never do this. But, in the top left part of your patch, I count 3 "send" message boxes that are patched directly to [netsend]. Delete those patch cables.
(Similarly, at the bottom of your patch, the line of objects coming directly down from [list trim] --> [route ch] --> [route 1 2 3 4] -- this is a part of my example patch that I had labeled with a comment saying "this will not work." Copying and pasting the non-working part is again going to be a source of confusion.)
~~
An OSC message has two parts.
- An address (for command) with slashes, e.g. /cs/chan/at/0.
- A list of arguments.
- The argument list always has datatype tags, even if you don't specify them.
- If you didn't write type tags, it will guess. In Pd, all numbers are floating-point, so outgoing OSC will format numbers as floating-point by default.
- The X32 documentation says that it expects an integer 1 or 0. So, in [oscformat], you can force a number in a specific position to be integer-formatted by giving "i" as the type tag.
So...
Which.. for the message [set /cs/chan/select/47(, might make sense, because there's the 47?
No, it's not the 47. The 47 is part of the command path. How do you know it's part of the command path? Because it's connected with slashes in the device docs. The command path is totally excluded from the type tags -- it's always a string.
It gets a bit confusing with [oscformat] because the vanilla OSC objects write both the OSC address and the arguments as lists (no slashes).
- [packOSC] way: [send /cs/chan/select/47(
- [oscformat] way: [set cs chan select 47, bang(
OK, let's look at those.
packOSC: 47 99 115 47 99 104 97 110 47 115 101 108 101 99 116 47 52 55 0 0 44 0 0 0 oscformat: 47 99 115 47 99 104 97 110 47 115 101 108 101 99 116 47 52 55 0 0 44 0 0 0
Notice that these are byte-for-byte identical. So these are just two different ways of expressing the same idea. (I do see in your screenshot where you're mixing and matching syntax, trying to use [oscformat] syntax with [packOSC] -- nope, this is not going to work. They have different programming interfaces.)
I suggest to slow down and do some smaller scale tests to make sure you can get the right result from the lighting board. Integration should come later.
hjh
-
ddw_music
@jbaker said:
Okay! I thought I was done... So I cleaned up the patch.
Since then, I realize my OSC commands to the lighting board aren't workingThere's no oscformat or packOSC before the lower netsend here, so, in that version of the patch, you aren't sending OSC-formatted messages to the lighting board. If the lighting board expects OSC, it won't respond to plain streams of ascii bytes.
hjh
-
ddw_music
@jbaker said:
pd is printing like it should!
... wha...? I don't see what's different but... glad it's working!
Now... I guess.. How can I get the 0 or 1 value into the patch?
Pretty much like this -- the [pd ch1] etc. boxes just do
[inlet]
|
[route mix]
|
[route on]
|
[outlet]Think of the OSC address space like a tree. 'ch' says it's a channel-related message. That branch of the tree splits off into a branch for each channel. Then each channel has properties or commands, of which one is 'mix' and below that, 'on' is one of many properties. [route] "peels off" each descriptor one by one and you can build the responses literally as a tree.
hjh
PS I didn't use MrPeach in this example bc I'm too lazy to install it.
-
ddw_music
Btw from jbaker's screenshots:
- Pd is definitely receiving a message from SC sent back to the Pd port, on the local machine (so, netsend isn't the problem).
- SC is receiving a reply back from the X32, confirming that the X32 is sending back to the originating port.
- But Pd netsend seems not to be receiving on the same port from the X32.
One difference is that the Pd vs SC test was on localhost, hence nothing to block traffic. (Why wasn't the X32 reply blocked for SC? SC doesn't randomize its outgoing port.)
I still think something in the OS is blocking the messages from the X32, but only for Pd.
hjh
-
ddw_music
@jbaker said:
I think you're right about the python script... I've finally looked.
It looks like it's sending OSC to 10023, and...it kind of looks like it's receiving on port 1024..? I'll try a [netreceive 1024] object and see what happens.Python docs say that the number given to recv is the size of the receive buffer, not the port.
The snippet from the X32 docs that you posted is unambiguous: replies are sent back to the requester's IP and port. So the netsend right-outlet approach should be correct.
Everybody gets their head tied in knots over send/receive ports.
When you connect a netsend, this is giving the IP and port TO which messages will be sent: TO port 10023. The message packet itself contains the sender's IP and port. In Pd, the FROM port is chosen randomly and AFAIK there is no way to know it -- so there's no way to open a netreceive on Pd's sending port. So let's say Pd chose port 45227. You send a message to the X32 and the packet includes your computer's IP and port 45227. The X32 (per documentation that you showed) should send its reply to the computer's IP and port 45227, where it would come out the netsend's right outlet.
I'm still suspecting firewall here. You said it's working on the Pi -- if the Pi isn't running a firewall but your computer is, that could block incoming messages.
"Suspecting" may be too strong -- at least, it's necessary to rule that out. (One not-so-ideal thing about Pd's use of random port numbers is that, in this case, you'd have to open a wide range of ports, or disable the firewall. If you could specify Pd's sending port, then you could open only that port in the firewall... but you don't know which one to open, so you'd have to open thousands of them.)
just the [netsend] on the left of the screenshot below........ it must be told to use the same port for send and receive...... so [connect port sameport(
That doesn't sound quite right to me. Pd here should send to 10023, but it will be sending from a port of its choosing, which isn't 10023. The X32 is sending back to the originating port (not to its own receiving port). So I think "connect aaa.bb.cc.ddd 10023 10023" would not work. The replies from the X32 will not be going to port 10023 on the computer.
hjh
-
ddw_music
@jbaker said:
@ddw_music I'm guessing that the X32 isn't replying on the same port we're sending to (with pd), but that's also an assumption.
There are basically two possibilities here:
- The X32 sends its replies to a port of your choosing. If that's the case, then there must be a configuration option for "port" somewhere on the X32.
- If there isn't place to configure the port, then it would pretty much have to be sending back to the Pd sending port. (It would make no sense to send to some arbitrary port that you have no control over and that is different from the sending port.)
That Python script should tell you whether it's receiving OSC on the same port from which it's sending, or on a different port.
One other thing to check -- are you 100% certain that the Pd machine's firewall is not blocking high port numbers?
When you "connect" a [netsend], the port number specified in the "connect" message is the port to which messages are sent. The from port (Pd side) isn't specified in this message, and (AFAIK) it's chosen randomly. If you have a firewall that allows traffic on only a few specific ports, that could be a problem for randomly-chosen ports.
The X32 Live Toolbox is receiving, but maybe that's operating on a specific port that was previously opened in the firewall.
You might also try SuperCollider for a test. SC by default sends and receives on port 57120. So you could test "reply to same port" like this:
n = NetAddr("10.136.124.112", 10023); OSCdef(\ch02, { |msg, time, addr| msg.debug("got it"); }, '/ch/02/mix/on'); n.sendMsg("/ch/02/mix/on");
... and if the X32 replied to the same port, you should see "got it: [ /ch/02/mix/on, 1_or_0 ]" in the console window.
Whenever I try to send pd messages with tilda's I get errors though.
Don't. [oscformat] handles that for you.
I am not sure that the return data is working with udp
It does, actually.
addr.sendMsg
at left tells SC to send back to the Pd port where the message came from, and it comes through [netsend]'s right outlet just fine.hjh
-
ddw_music
@whale-av said:
@ddw_music It seems that maybe data can be requested from the X32...
With apologies but why do you keep addressing these to me? It's not my device or my question.
I was trying to fill in some gaps for jbaker about how to use the Pd OSC objects. My interest ends there, tbh.
hjh
-
ddw_music
For testing purposes here, you have two [print reassembled] -- meaning that you have no idea which one is printing. If you give them different names, the console window output will be less confusing.
I'm pretty sure [netreceive -u -b] isn't doing anything because it hasn't opened a port.
[oscparse] does not give you
/ch/01/mix/on
-- it gives youch 01 mix on
-- which has to be peeled apart by multiple [route] objects. Then there's the fun thing about numbers in OSC command paths. So I'd suggest:Because the device has numbers in the path, you have to use the [fudiformat] / [fudiparse] workaround. Don't worry if you don't understand why, just, do not delete them.
(The netsend right outlet thing is based on the assumption that the device is sending back to the same port that Pd sent from. This might not be true -- in that case, you'd need to find out how the device is sending and configure the patch accordingly. Also double check to be sure the firewall isn't blocking Pd from receiving.)
hjh
-
ddw_music
@whale-av said:
@ddw_music It looks as though the X32 requires a type tag string in osc messages, where the the data atoms after the message header /this-that are defined as integer(32) float(32) string and blob.
@jbaker ^^ this -- it means that your guess about putting slashes between all the parts of the message wasn't a valid approach.
@whale-av indeed, I thought it was a bit odd to have these long command paths with data in them. It definitely makes more sense with typetagged arguments.
hjh
-
ddw_music
@jbaker said:
So... I'm trying this and not seeing any messages print.
You need a bang.
OSC's "normal" case is to send many messages with the same command path, with different argument data. So, oscformat sends only when receiving data values in the inlet.
To send a data-less OSC message, command path only, use a bang instead of data.
To make that more convenient, use Pd's messaging logic to bang automatically:
So any message you send into the [pd] subpatch will do "set" then "bang."
Is the 57120 a common udp return port for OSC devices?
Well, I don't have your device, so I wasn't testing on the same port.
Everything above is totally independent of the port number.
hjh
-
ddw_music
@jbaker said:
I can't seem to get return values from the X32. With the X32 livetoolkit software I know that sending [/ch/02/mix/on] will return [/ch/02/mix/on ,i 1]. The send command doesn't need a value type (float, int, etc.), but the return value contains an int, which is either 1 or 0, which represents the mute as on or off. I can't get any return values from the board. I'm trying UDP with netsend -u -b 10.136.124.112 10023.
I think the receiving bit should look like this:
If I send back to the same port e.g.
/hi/back 1
then, after list trim, the message looks likehi back 1
.[fudiformat] / [fudiparse] is a workaround to handle the numbers in the OSC path.
BTW those "send /xxx/yyy/zzz" -- pretty sure that's not standard OSC -- I crashed SuperCollider trying to send to it that way.
This is the right way to send a properly formatted OSC message. Leading zeroes can be escaped, e.g.,
set ch \02 mix on, bang
would send/ch/02/mix/on
.hjh
-
ddw_music
@jamcultur said:
I'm creating a wavetable using sinesum to write harmonics to an array, which works fine for integer overtones. I'd also like to be able to be able to write non-integer overtones and undertones to the array.
If you put a 2.5 cosine harmonic into an array (2.5 cycles spanning the array's length), then the beginning of this wave will be +1 and, at the end of the array, -1. So you'd get two full cycles, then half a cycle going down, and then jump abruptly to the start again. So, non-integer partials will always behave like hard sync.
If you want that hard sync sound, that's fine, but if you want a smooth wave at 2.5x the fundamental frequency, it's not possible with a wavetable (unless you size the wavetable according to the LCM of the partial ratios and scale all the ratios up to be integers).
hjh
-
ddw_music
@oid said:
Because you skipped over learning the basics, objects have hot and cold inlets..,
This idiom, of sending values forward to be stored passively, is critical to successful patching but also seems to be difficult to grasp. Taking myself as example, while I wasn't a CS student, I think I know my way around an algorithm or two, but when I started teaching with Pd, it took me over a year to understand this well.
It's a crucial part of "the basics," but it does take some effort to really get it.
I've thought for a while that Collatz series are a good example of the awkwardness of patching for if-then-else, because a value is used separately in the "then" and "else" branches.
A simple SuperCollider Collatz series function is pretty clear and concise.
( f = { |x| while { x != 1 } { if(x.even) { x = x div: 2 } { x = x * 3 + 1 }; x.postln; } }; )
The thing that is difficult for patching to handle is that this variable 'x' is referenced in three places, and two of those are conditional -- if 'x' is a patching object, you can't just connect a single [f] box to all of its downstream paths because, in each iteration, one or the other needs to be suppressed.
One way is to set [spigot]s opposite Booleans, and push the value through both of them -- always try to go down both paths, but one of them is blocked.
( f = { |x| var cond; while { x != 1 } { cond = x.odd; if(cond.not) { x = x div: 2 }; if(cond) { // two ifs? hmm... x = x * 3 + 1 }; x.postln; } }; )
Another way is to push the value into separate [f] variables, but bang only one of them.
( f = { |x| var trueX, falseX; while { x != 1 } { trueX = x; // lol falseX = x; if(x.even) { x = trueX div: 2 } { x = falseX * 3 + 1 }; x.postln; } }; )
And a third way is to mimic [cyclone/gate] by binding the value and the condition together, and using [route] to dispatch.
( f = { |x| var bind; while { x != 1 } { bind = [x, x.even]; // 'pop' pops from the end, // similar to [route] popping from the start if(bind.pop) { x = bind[0] div: 2 } { x = bind[0] * 3 + 1 }; x.postln; } }; )
All three of these IMO read a bit awkwardly in code (though, using [cyclone/gate] would simplify the third one)... but they're structural necessities in the Max/Pd messaging layer. These are "basics" but not exactly intuitive -- a pedagogical problem.
hjh
-
ddw_music
@Wabot03 said:
this is the patch, The camera recognizes the fiducials, but I can't assign them to different MIDI values in Ableton. That is, each fiducial controls the same fader in Ableton.
- I don't have a TUIO, and I don't have the TuioClient object, so I have no idea how it behaves.
- I don't know the MIDI messages that Ableton is expecting.
- And, the patch you sent doesn't show any MIDI output objects, so I have no idea what you've tried.
So all I can do is (to the best that I can figure out from the available information) clarify what you need to do -- but you need to do the research. You need to figure out what are the messages coming from TUIO, and you need to figure out what MIDI messages should go to Ableton.
I can't do that for you. (Maybe somebody else on the forum could.)
TUIO side: I'd concentrate on the updateCursor messages. These are sending four numbers:
- First #: no idea
- Second #: no idea
- Third and fourth #s: X and Y
BTW your unpack should be [unpack f f f f], NOT $1 $2 $3 $4.
You'll need a chain of [route] objects:
[route updateCursor] // input is "updateCursor a b c d"
|
[route ****] // replace **** with a correct value for "a"
| // input is "a b c d"
[route ++++] // replace ++++ with a correct value for "b"
|
[unpack f f]^^ and here you have X and Y.
One of those [route] objects will distinguish the different fiducials. Then you can use many fiducial IDs in the same [route]:
[route 1 2 3 4] etc
But "1 2 3 4" will be different depending on the messages coming from TUIO. I have no visibility into that; you will have to find those numbers for yourself.
Then you need to scale those values on to the range 0 to 127 and send by MIDI.
hjh