synth: how to generate more than 2 tones simultaneously

Previous Topic Next Topic
 
classic Classic list List threaded Threaded
10 messages Options
Reply | Threaded
Open this post in threaded view
|

synth: how to generate more than 2 tones simultaneously

Brian Berge
i'm able to produce 2 tones through one playerindex variable (& one inindex variable), via left & right channels...but i need more than 2 tones at once.

i turned playerindex & inindex into arrays [0..15].  each of these 16 voices work normally in itself, but as soon as i ask to sound a second one, the previous one turns silent.

how can i get more than 1 of these 16 voices to sound at once?

(thank you!)
Reply | Threaded
Open this post in threaded view
|

Re: synth: how to generate more than 2 tones simultaneously

fredvs
Administrator
Hello and welcome to uos forum.

Not sure to understand, It would be easier if you could give the code that you used.

To play more than 2 tones at once you may create a player for each tone, assign with uos_AddFromSynth for each player and then play all the players together.

Something like this:

// Create the players:
uos_CreatePlayer(PlayerIndex1);
inindex1 :=  uos_AddFromSynth(PlayerIndex1, -1, -1, -1, 420, 420, -1, -1, -1, -1, -1, 0, -1, -1, -1);
uos_AddIntoDevOut(PlayerIndex1, -1, -1, -1, -1, 0, -1, -1)
 
uos_CreatePlayer(PlayerIndex2);
inindex2 :=  uos_AddFromSynth(PlayerIndex2, -1, -1, -1, 600, 600, -1, -1, -1, -1, -1, 0, -1, -1, -1);
uos_AddIntoDevOut(PlayerIndex2, -1, -1, -1, -1, 0, -1, -1)

uos_CreatePlayer(PlayerIndex3);
inindex3 :=  uos_AddFromSynth(PlayerIndex3, -1, -1, -1, 800, 800, -1, -1, -1, -1, -1, 0, -1, -1, -1);
uos_AddIntoDevOut(PlayerIndex3, -1, -1, -1, -1, 0, -1, -1)

// Play all the players together:
uos_Play(PlayerIndex1);
uos_Play(PlayerIndex2);
uos_Play(PlayerIndex3);
---------------------------

You may try the consolesynth.pas as demo ( but it is for only one sound).

Fre;D
Reply | Threaded
Open this post in threaded view
|

Re: synth: how to generate more than 2 tones simultaneously

fredvs
Administrator
Re-hello.

It depends of your sound card but it is possible that, if you use lot of players, to have some distortion.
If it is the case, try to use a lower sample rate at creating each player, for example 10025 (in place of default 44100) and so the value for example A/La =440/4 = 110.
Reply | Threaded
Open this post in threaded view
|

Re: synth: how to generate more than 2 tones simultaneously

Brian Berge
well, i tried to conform better to your example.  now i only get sound for the first 4 tones in the series--the remaining 12 are silent.

here is the source (adapted from 1 of the examples):
_____

program synth2morevoices;  {$mode objfpc}{$H+}  {$DEFINE UseCThreads}
uses  {$IFDEF UNIX}  cthreads,  {$ENDIF}  Classes, SysUtils, CustApp, uos_flat;
type TuosConsole = class (TCustomApplication)
                      private   procedure   ConsolePlay;
                      protected procedure   doRun; override;
                      public    constructor Create (TheOwner: TComponent); override;
                   end;
var i, res                   : integer;
    ordir, opath, PA_FileName: string;
    PlayerIndex, inindex     : array [0..15] of integer;
    freq, freqinc            : real;

   {TuosConsole}
procedure TuosConsole.ConsolePlay;
begin
   ordir := IncludeTrailingBackslash (ExtractFilePath (ParamStr (0)));
   {$IFDEF Windows}
      {$if defined(cpu64)}
         PA_FileName := ordir + 'lib\Windows\64bit\LibPortaudio-64.dll';
      {$else}
         PA_FileName := ordir + 'lib\Windows\32bit\LibPortaudio-32.dll';
      {$endif}
   {$ENDIF}
   {$if defined (CPUAMD64) and defined (linux     )}
      PA_FileName := ordir + 'lib/Linux/64bit/LibPortaudio-64.so';
   {$ENDIF}
   {$if defined (cpu86   ) and defined (linux     )}
      PA_FileName := ordir + 'lib/Linux/32bit/LibPortaudio-32.so';
   {$ENDIF}
   {$if defined (linux   ) and defined (cpuarm    )}
      PA_FileName := ordir + 'lib/Linux/arm_raspberrypi/libportaudio-arm.so';
   {$ENDIF}
   {$if defined (linux   ) and defined (cpuaarch64)}
      PA_FileName := ordir + 'lib/Linux/aarch64_raspberrypi/libportaudio_aarch64.so';
   {$ENDIF}
   {$IFDEF freebsd}
      {$if defined(cpu64)}
         PA_FileName := ordir + 'lib/FreeBSD/64bit/libportaudio-64.so';
      {$else}
         PA_FileName := ordir + 'lib/FreeBSD/32bit/libportaudio-32.so';
      {$endif}
   {$ENDIF}
   {$IFDEF Darwin}
      {$IFDEF CPU32}
         opath := ordir;
         opath := copy(opath, 1, Pos('/UOS', opath) - 1);
         PA_FileName := opath + '/lib/Mac/32bit/LibPortaudio-32.dylib';
      {$ENDIF}
      {$IFDEF CPU64}
         opath := ordir;
         opath := copy(opath, 1, Pos('/UOS', opath) - 1);
         PA_FileName := opath + '/lib/Mac/64bit/LibPortaudio-64.dylib';
      {$ENDIF}
   {$ENDIF}

      // Load the libraries (here only portaudio is needed)
      //    function uos_loadlib (PortAudioFileName, SndFileFileName, Mpg123FileName, Mp4ffFileName, FaadFileName, opusfilefilename:: PChar): LongInt;
   res := uos_LoadLib (PChar (PA_FileName), nil, nil, nil, nil, nil);
   writeln ('Result of loading (if 0 => ok ):  ' + IntToStr (res));
   writeln ((uos_getinfolibraries ()));
   if res = 0 then begin
         //// Create the player.
         //// PlayerIndex:  from 0 to what your computer can do!
         //// If PlayerIndex exists already, it will be overwriten...
      for i := 0 to 15 do begin
         PlayerIndex [i] :=  0;
         inindex     [i] := -1;
         if uos_CreatePlayer (PlayerIndex [i]) then
            inindex [i] := uos_AddFromSynth (PlayerIndex [i], -1,  -1, -1,  0.00001, 0.00001,  -1, -1,  -1,  -1, -1,  0,  -1, -1, -1);
               {function uos_AddFromSynth (PlayerIndex                                          : cint32;
                                           Channels, WaveTypeL, WaveTypeR                       : integer;
                                            FrequencyL, FrequencyR, VolumeL, VolumeR             : float;
                                           duration, NbHarmonics, EvenHarmonics,
                                              OutputIndex, SampleFormat, SampleRate, FramesCount: cint32): cint32;
                  // Add a input from Synthesizer with custom parameters
                  // Channels     :  default:  -1  (2)  (1 = mono, 2 = stereo)
                  // WaveTypeL    :  default:  -1  (0)  (0 = sine-wave, 1 = square-wave, used for mono & stereo)
                  // WaveTypeR    :  default:  -1  (0)  (0 = sine-wave, 1 = square-wave, used for stereo, ignored for mono)
                  // FrequencyL   :  default:  -1  (440 Hz)  (Left frequency, used for mono)
                  // FrequencyR   :  default:  -1  (440 Hz)  (Right frequency, used for stereo, ignored for mono)
                  // VolumeL      :  default:  -1  (=    1)  (from 0 to 1) => volume left
                  // VolumeR      :  default:  -1  (=    1)  (from 0 to 1) => volume right (ignored for mono)
                  // Duration     :  default:  -1  (= 1000)                => duration in msec  (0 = endless)
                  // NbHarmonics  :  default:  -1  (=    0)  Number of Harmonics
                  // EvenHarmonics:  default:  -1  (=    0) (0 = all harmonics, 1 = Only even harmonics)
                  // OutputIndex  :  Output index of used output
                        // -1: all output, -2: no output, other cint32 refer to
                        //    a existing OutputIndex
                        //    (if multi-output then OutName = name of each output separated by ';')
                  // SampleFormat :  default:  -1  (0: Float32) (0: Float32, 1: Int32, 2: Int16)
                  // SampleRate   :  delault:  -1  (44100)
                  // FramesCount  :  -1  default: 1024
                  // result       :  Input Index in array  -1 = error}
                  {$if defined(cpuarm) or defined(cpuaarch64)}  // need a lower latency
                     if    uos_AddIntoDevOut (PlayerIndex [i], -1,  0.3, -1, -1, 0, -1, -1) > -1 then
                     {$else}
                        if uos_AddIntoDevOut (PlayerIndex [i], -1, -1  , -1, -1, 0, -1, -1) > -1 then
                  {$endif}
            //// add a Output into device with custom parameters
               //////////// PlayerIndex:  Index of a existing Player
               // result:  -1 nothing created, otherwise Output Index in array
         begin
               /////// everything is ready, here we are, lets play it...
            uos_Play (PlayerIndex [i]);
//          uos_InputSetSynth (PlayerIndex [i], inindex [i], -1, -1,  0.00001, 0.00001,  -1, -1,  0,  -1, -1, True);
               {procedure InputSetSynth (InputIndex                              : cint32;
                                         WaveTypeL, WaveTypeR                    : integer;
                                         FrequencyL, FrequencyR, VolumeL, VolumeR: float;
                                         duration, NbHarmonic, EvenHarmonics     : cint32;
                                         Enable                                  : boolean);
                  // InputIndex   :  one existing input index
                  // WaveTypeL    :  do not change:  -1  (0 = sine-wave, 1 = square-wave, used for mono & stereo)
                  // WaveTypeR    :  do not change:  -1  (0 = sine-wave, 1 = square-wave, used for stereo, ignored for mono)
                  // FrequencyL   :  do not change:  -1  (Left frequency, used for mono)
                  // FrequencyR   :  do not change:  -1  (440 Hz) (Right frequency, used for stereo, ignored for mono)
                  // VolumeL      :  do not change:  -1  (= 1)  (from 0 to 1) => volume left
                  // VolumeR      :  do not change:  -1         (from 0 to 1) => volume rigth (ignored for mono)
                  // Duration     :  in msec (-1 = do not change)
                  // NbHarmonic   :  Number of Harmonics (-1 not change)
                  // EvenHarmonics:  default:  -1  (= 0)  (0 = all harmonics, 1 = only even harmonics)
                  // Enable       :  true or false}
         end;
      end;
      freq    := 220;  {A3}
      freqinc := freq;
      for i := 0 to 15 do begin
         writeln (i:2);
         uos_InputSetSynth (PlayerIndex [i], inindex [i],  -1, -1,  freq, freq,  -1, -1,  1000,  -1, -1, True);
         sleep (300);
         freq := freq + freqinc;
      end;
      sleep (600);
      for i := 0 to 15 do uos_stop (PlayerIndex [i]);
      writeln (IntToStr (GetCPUCount ()));
      sleep (900);
   end;
end;

procedure TuosConsole.doRun;
begin
   ConsolePlay;
   uos_free;
   Terminate;
end;

constructor TuosConsole.Create (TheOwner: TComponent);
begin
   inherited Create (TheOwner);
   StopOnException := True;
end;

var Application: TUOSConsole;
begin
   Application       := TUOSConsole.Create (nil);
   Application.Title := 'Console Synthesizer';
   Application.Run;
   Application.Free;
end.
Reply | Threaded
Open this post in threaded view
|

Re: synth: how to generate more than 2 tones simultaneously

Brian Berge
In reply to this post by fredvs
p.s. i'm on a pretty new lenovo laptop, running windows 11 (in case that helps re. sound card)
Reply | Threaded
Open this post in threaded view
|

Re: synth: how to generate more than 2 tones simultaneously

fredvs
Administrator
Hello.

Try with this:

program synth2morevoices;  {$mode objfpc}{$H+}  {$DEFINE UseCThreads}  

uses  {$IFDEF UNIX}  cthreads,  {$ENDIF}  Classes, SysUtils, CustApp, uos_flat;
type TuosConsole = class (TCustomApplication)
                      private   procedure   ConsolePlay;
                      protected procedure   doRun; override;
                      public    constructor Create (TheOwner: TComponent); override;
                   end;
var i, res                   : integer;
    ordir, opath, PA_FileName: string;
    PlayerIndex, inindex     : array [0..15] of integer;
    freq, freqinc            : real;

   {TuosConsole}
procedure TuosConsole.ConsolePlay;
begin
   ordir := IncludeTrailingBackslash (ExtractFilePath (ParamStr (0)));
   {$IFDEF Windows}
      {$if defined(cpu64)}
         PA_FileName := ordir + 'lib\Windows\64bit\LibPortaudio-64.dll';
      {$else}
         PA_FileName := ordir + 'lib\Windows\32bit\LibPortaudio-32.dll';
      {$endif}
   {$ENDIF}
   {$if defined (CPUAMD64) and defined (linux     )}
      PA_FileName := ordir + 'lib/Linux/64bit/LibPortaudio-64.so';
   {$ENDIF}
   {$if defined (cpu86   ) and defined (linux     )}
      PA_FileName := ordir + 'lib/Linux/32bit/LibPortaudio-32.so';
   {$ENDIF}
   {$if defined (linux   ) and defined (cpuarm    )}
      PA_FileName := ordir + 'lib/Linux/arm_raspberrypi/libportaudio-arm.so';
   {$ENDIF}
   {$if defined (linux   ) and defined (cpuaarch64)}
      PA_FileName := ordir + 'lib/Linux/aarch64_raspberrypi/libportaudio_aarch64.so';
   {$ENDIF}
   {$IFDEF freebsd}
      {$if defined(cpu64)}
         PA_FileName := ordir + 'lib/FreeBSD/64bit/libportaudio-64.so';
      {$else}
         PA_FileName := ordir + 'lib/FreeBSD/32bit/libportaudio-32.so';
      {$endif}
   {$ENDIF}
   {$IFDEF Darwin}
      {$IFDEF CPU32}
         opath := ordir;
         opath := copy(opath, 1, Pos('/UOS', opath) - 1);
         PA_FileName := opath + '/lib/Mac/32bit/LibPortaudio-32.dylib';
      {$ENDIF}
      {$IFDEF CPU64}
         opath := ordir;
         opath := copy(opath, 1, Pos('/UOS', opath) - 1);
         PA_FileName := opath + '/lib/Mac/64bit/LibPortaudio-64.dylib';
      {$ENDIF}
   {$ENDIF}

      // Load the libraries (here only portaudio is needed)
      //    function uos_loadlib (PortAudioFileName, SndFileFileName, Mpg123FileName, Mp4ffFileName, FaadFileName, opusfilefilename:: PChar): LongInt;
   res := uos_LoadLib (PChar (PA_FileName), nil, nil, nil, nil, nil);
   writeln ('Result of loading (if 0 => ok ):  ' + IntToStr (res));
   writeln ((uos_getinfolibraries ()));
   if res = 0 then begin
         //// Create the player.
         //// PlayerIndex:  from 0 to what your computer can do!
         //// If PlayerIndex exists already, it will be overwriten...
      for i := 0 to 15 do begin
       
         if uos_CreatePlayer (i) then
            inindex [i] := uos_AddFromSynth (i, -1,  -1, -1,  -1, -1,  -1, -1,  -1,  -1, -1,  0,  -1, -1, -1);
               {function uos_AddFromSynth (PlayerIndex                                          : cint32;
                                           Channels, WaveTypeL, WaveTypeR                       : integer;
                                            FrequencyL, FrequencyR, VolumeL, VolumeR             : float;
                                           duration, NbHarmonics, EvenHarmonics,
                                              OutputIndex, SampleFormat, SampleRate, FramesCount: cint32): cint32;
                  // Add a input from Synthesizer with custom parameters
                  // Channels     :  default:  -1  (2)  (1 = mono, 2 = stereo)
                  // WaveTypeL    :  default:  -1  (0)  (0 = sine-wave, 1 = square-wave, used for mono & stereo)
                  // WaveTypeR    :  default:  -1  (0)  (0 = sine-wave, 1 = square-wave, used for stereo, ignored for mono)
                  // FrequencyL   :  default:  -1  (440 Hz)  (Left frequency, used for mono)
                  // FrequencyR   :  default:  -1  (440 Hz)  (Right frequency, used for stereo, ignored for mono)
                  // VolumeL      :  default:  -1  (=    1)  (from 0 to 1) => volume left
                  // VolumeR      :  default:  -1  (=    1)  (from 0 to 1) => volume right (ignored for mono)
                  // Duration     :  default:  -1  (= 1000)                => duration in msec  (0 = endless)
                  // NbHarmonics  :  default:  -1  (=    0)  Number of Harmonics
                  // EvenHarmonics:  default:  -1  (=    0) (0 = all harmonics, 1 = Only even harmonics)
                  // OutputIndex  :  Output index of used output
                        // -1: all output, -2: no output, other cint32 refer to
                        //    a existing OutputIndex
                        //    (if multi-output then OutName = name of each output separated by ';')
                  // SampleFormat :  default:  -1  (0: Float32) (0: Float32, 1: Int32, 2: Int16)
                  // SampleRate   :  delault:  -1  (44100)
                  // FramesCount  :  -1  default: 1024
                  // result       :  Input Index in array  -1 = error}
                  {$if defined(cpuarm) or defined(cpuaarch64)}  // need a lower latency
                     uos_AddIntoDevOut (i, -1,  0.3, -1, -1, 0, -1, -1) ;
                     {$else}
                     uos_AddIntoDevOut (i, -1, 0.3  , -1, -1, 0, -1, -1) ;
                  {$endif}
         end;
     
      freq    := 220;  {A3}
      freqinc := freq;
      for i := 0 to 15 do begin
         uos_InputSetSynth (i, 0,  -1, -1,  freq, freq,  -1, -1,  -1,  -1, -1, True);
         sleep (300);
          writeln(i);
            uos_Play (i);
         freq := freq + freqinc;
      end;
      sleep (600);
     for i := 0 to 15 do uos_stop (i);
      writeln (IntToStr (GetCPUCount ()));
      sleep (900);
    end;
end;

procedure TuosConsole.doRun;
begin
   ConsolePlay;
   uos_free;
   Terminate;
end;

constructor TuosConsole.Create (TheOwner: TComponent);
begin
   inherited Create (TheOwner);
   StopOnException := True;
end;

var Application: TUOSConsole;
begin
   Application       := TUOSConsole.Create (nil);
   Application.Title := 'Console Synthesizer';
   Application.Run;
   Application.Free;
end.
Reply | Threaded
Open this post in threaded view
|

Re: synth: how to generate more than 2 tones simultaneously

fredvs
Administrator
In reply to this post by fredvs
Re-hello.

If you wan that all the players play together set the duration to 0 in uos_InputSetSynth, like this:

   uos_InputSetSynth (i, 0,  -1, -1,  freq, freq,  -1, -1,  0,  -1, -1, True);
Reply | Threaded
Open this post in threaded view
|

Re: synth: how to generate more than 2 tones simultaneously

Brian Berge
oh, lovely!  that's beautiful!

now, at the end, the program doesn't exit
Reply | Threaded
Open this post in threaded view
|

Re: synth: how to generate more than 2 tones simultaneously

Brian Berge
wait, i'm wrong!  it exited fine.

sir, thank you so much (for everything)!
Reply | Threaded
Open this post in threaded view
|

Re: synth: how to generate more than 2 tones simultaneously

fredvs
Administrator
You are welcome!

Fre;D