On Sat, Mar 6, 2010 at 9:03 AM, Scott Hardin <sc...@hnsc.de> wrote:
> Hi Allen,
>
> Thanks for your response.
>
> After digging a little deeper, I think I have found the right places to hook into things.
>
> Since KeyStack already tracks the current active keys, I'll add a GetCurrentNotes() to return a list of all active notes.
>
> Then, in the Controller class I will create an array for storing multiple instances of the KeyboardOscillator objects -- probably the same size as the array in KeyStack, which is 64. I'll then need to add some logic to know which note is stored at which index. As an alternative, I could make the array size equal to the maximum number of notes (88 on a normal piano) and use the note number from the noteOn and noteOff methods as the array index.
>
> Lastly, in Controller::GetSample(), instead of "float value = combined_osc_.GetValue();", I'll need to run GetValue on each of the active KeyboardOscillator objects and, if I understand it correctly, I just need to add the values together before continuing with the clip, etc. in GetSample().
>
> Am I missing something significant?
>
> With best regards,
>
> Scott
>
> On Mar 6, 2010, at 17:25 , Allen Porter wrote:
>
>> Hi Scott,
>>
>> Yes, I would use multiple oscillator objects set to different
>> frequencies. I found that using AudioQueue added extra latency since
>> its meant to just be as simple as possible -- not as fast as possible.
>> Mobilesynth originally used AudioQueue, but was switched to use the
>> AudioComponent stuff.
>>
>> If you want to release your findings to a wider audience then consider
>> posting to mobil...@googlegroups.com
>>
>> -allen
>>
>> On Fri, Mar 5, 2010 at 12:01 AM, Scott Hardin <sc...@hnsc.de> wrote:
>>> Hi Allen,
>>>
>>> thank you for making your project open source. It has provided me with a great basis for fiddling around with some ideas in my spare time.
>>>
>>> In my project, I'm trying to figure out the best way to make the synthesizer play more than one key at a time so I can do chords. I'm considering trying to use AudioQueue or just trying to create more oscillator objects that will be used simultaneously. What are your thoughts on this? I saw that there are already two oscillators assigned to the current note to give it a thicker sound, so I was looking at expanding that.
>>>
>>> I'd be thankful for any suggestions.
>>>
>>> With best regards,
>>>
>>> Scott
>>>
>>> --
>>> Scott T. Hardin <sc...@hnsc.de>
>>> Marburg, Germany
>>
>>
>> --
>> -allen
>
>
> --
> Scott Hardin <sc...@hnsc.de>
> Marburg, Germany
>
>
>
>
--
-allen
On Thu, Mar 11, 2010 at 12:48 AM, Scott Hardin <sc...@hnsc.de> wrote:
> Hi Allen,
>
> Thanks again for the input. I've managed to move the attributes into the KeyBoardOscillator object and I can get multiple sounds at the same time. What I'm having trouble with at the moment is understanding just when a key should be silent.
>
> My original thought was that if a key were off, then GetValue() would return zero. Here's an excerpt from Controller::GetSample():
>
> ...
> float value = 0;
> for (int i = kNumMin; i < kNumMax; i++) {
> value += combined_oscs_[i]->GetValue();
> }
> ...
>
> This works partially. When I click on the first note, it plays correctly. When I click on a second note (not the two notes simultaneously), I hear both notes. The previous notes still sound, even when not pressed, whenever a new note is pressed.
>
> If I explicitly add an attribute to the KeyboardOscillator instance to track whether a key has been pressed and put it in Controller::GetSample() as follows, I only get the notes actively pressed, but the sound chops off exactly when the key is released, because the lag processor is no longer used to decay the release:
>
> ...
> float value = 0;
> for (int i = kNumMin; i < kNumMax; i++) {
> if ( combined_oscs_[i]->IsNoteOn ) {
> value += combined_oscs_[i]->GetValue();
> }
> }
> ...
>
> What I'm guessing is that the Envelope (envelope_) in the LagProcessor isn't switching to the "DONE" state when playing the key is finished. The code at the beginning of Controller::GetSample() that exits if either volume_envelope or filter_envelope is released works and correctly skips the code when nothing is to be played, so shouldn't there be a similar mechanism in the LagProcessor?
>
> Am I still on the right track? Any nudges in the right direct are greatly appreciated.
I think that since the lag processor is only used to control frequency
it shouldn't impact the volume. Sounds like you've got all the parts
code all figured out, but there is something subtle going on. I
suggest writing an additional unit test -- that is the way i've
figured out bugs like this in the past. Hopefully you can hack up one
if the existing tests without much trouble. It seems easier to
reproduce these things with a really small sample size so you can add
in print statements or use a debugger.
>
> With best regards,
>
> Scott
>
> P.S.: I tried to CC the mailing list, but it bounced.
I wonder if the group is bouncing your posts because you guys are not members...
Roasy,
It seems like it might be easier to reason about if you try to combine
the two sine waves into a single signal instead of writing them
separately. In general I to keep what I write to provided CoreAudio
data structures as simple as possible because as soon as I start
changing the way I do it, it stops working and I don't understand what
i'm doing wrong :)
On Tue, Mar 23, 2010 at 4:39 PM, Roasty <roet...@gmail.com> wrote:
> Hi Scott (sorry Allen, I've only your address),
>
> Any luck with getting this to work?
>
> In focusing on the callback to generate 2 tones simultaneously, I'm
> stuck.
> I've modified the callback function from Apple's
> "iPhoneMultichannelMixer" sample code:
> static OSStatus renderInput(void *inRefCon,
> AudioUnitRenderActionFlags *ioActionFlags,
> const AudioTimeStamp *inTimeStamp,
> UInt32 inBusNumber,
> UInt32 inNumberFrames,
> AudioBufferList *ioData)
> {
> SoundBufferPtr sndbuf = (SoundBufferPtr)inRefCon;
> UInt32 bufSamples = sndbuf[inBusNumber].numFrames;
> AudioUnitSampleType *outA = (AudioUnitSampleType *)ioData-
>>mBuffers[0].mData;
> AudioUnitSampleType *outB = (AudioUnitSampleType *)ioData-
>>mBuffers[1].mData;
> UInt32 sample = sndbuf[inBusNumber].sampleNum;
> static int phase = 0;
> float waves;
>
> for (UInt32 i = 0; i < inNumberFrames; ++i) {
> waves = 0;
> if (1 == inBusNumber) {
> outA[i] = 0;
> waves += sin(kWaveform * 440.0f * phase); // A 440
> waves *= 32500/2;
> outB[i] = (SInt16)waves;
> outB[i] += outB[i]<<16;
> } else {
> waves += sin(kWaveform * 660.0f * phase); // E above A 440
> waves *= 32500/2;
> outA[i] = (SInt16)waves;
> outA[i] += outA[i]<<16;
> outB[i] = 0;
> }
> if (sample >= bufSamples) sample = 0;
> phase++;
> }
> sndbuf[inBusNumber].sampleNum = sample;
> return noErr;
> }
>
> Instead of creating a nice perfect 5th sound (A + E), I hear one nasty
> (modulated) tone.
> When I experiment with 2 generated sine tone samples instead (ex:
> a440.aif & e660.aif) it sounds perfect.
>
> Any idea why this is happening?
>
> Cheers,
> Roasty
--
-allen
It's great to read what others are doing. I'll soon start with polyphonic output too... so it would be nice if you all joined the group so I could read about your results.
To let you know what I've done so far (last month): I used the audio output class from mobilesynth and implemented a "Karplus Strong" plucked string sound by writing an objective C class that implements a generateSamples method.
I implemented this with integers instead of floating point numbers. It works fine, although it is only proof of concept.
Next step for me will be cleaning the code (removing proof of concept experiments from it), and then adding polyphonic output.
I found it very surprising that the number you are supposed to generate (in generateSamples) is 32 bits. This makes it easy to do integer maths, I can just implement all my internal functions as 16 bits integers, and wherever I need to multiply with a fraction, just multiplty and shift the bits to the right to simulate a division.
So in this case I'd also go for a solution adding and mixing the sine waves myself instead of using CoreAudio.
regards,
Jan.
> --
> You received this message because you are subscribed to the Google Groups "mobilesynth" group.
> To post to this group, send email to mobil...@googlegroups.com.
> To unsubscribe from this group, send email to mobilesynth...@googlegroups.com.
> For more options, visit this group at http://groups.google.com/group/mobilesynth?hl=en.
>