Answers.Body: <p>An alternative would be to draw the pitch over time —as you did it in your example picture— and generate the associated sound. This can be straight-forward sometimes, depending of your constraints.</p>
  <p>You can do this easily if you are familiar with <a href="https://cycling74.com/downloads" rel="noreferrer">Max</a> or <a href="https://puredata.info/" rel="noreferrer">Pure Data</a> programming languages (draw the pitch, select the speed it should be read, link the drawing to the frequency of the sinusoidal generator).</p>
  <p>You could also use a more-friendly-interface software such as <a href="https://www.klingbeil.com/spear/" rel="noreferrer">Spear</a>; it says &quot;Features include: pencil tool for drawing&quot;:</p>
  <p><a href="https://i.sstatic.net/ruHPD.png" rel="noreferrer"><img src="https://i.sstatic.net/ruHPD.png" alt="enter image description here" /></a>
  (picture from <a href="https://www.semanticscholar.org/paper/Software-for-spectral-Analysis%2C-Editing%2C-and-Klingbeil/505d336033e290066c8cf114194a5c530f1895e4" rel="noreferrer">Klingbeil 2005</a>)</p>
  
Answers.ContentLicense: CC BY-SA 4.0
Answers.CreationDate: 2022-07-22T15:57:15.297Z
Answers.Text: This is a great answer. As well as Max & Pure Data, I would recommend to add **SuperCollider** (my favourite). I would expect there to be a good Python library too, but no - there are a few options but none of them very mature/dependable
Answers.UserDisplayName: Dan Stowell
Answers.ContentLicense: CC BY-SA 4.0
Answers.CreationDate: 2022-07-21T10:07:03.557Z
Answers.LastActivityDate: 2022-07-21T12:31:44.440Z
Answers.LastEditDate: 2022-07-21T12:31:44.440Z
Answers.UserDisplayName: Noil
Answers.Body: <p>Edited 2022-8-9: the bug is fixed in the new release published yesterday August 8, 2022, version 39.</p>
  <p>Edited 2022-7-27: a bug discovered after posting this answer prevents a newly created whistle to not be stored properly in the persistent database and therefore the new whistle frequencies are lost when the app is closed; the bug is getting fixed and in the mean time please use the editor while taking this into consideration; a new version will be released when the bug is fixed.</p>
  <p>Original post:
  Here's an open source tool to generate such sounds, the source code is in gitlab: DC Dolphin Communicator, free for Android, from <a href="https://play.google.com/store/apps/details?id=sm.app.dc" rel="nofollow noreferrer">https://play.google.com/store/apps/details?id=sm.app.dc</a> - I wrote it. It may do what you need, although the app is also designed for whistle recognition. It is best used on a tablet instead of a phone.</p>
  <p>It has an editor that lets you build whistles within a ~0.5 kHz to 11 kHz range. You need to defined the frequency values in Hz at each 40th of a second. You give the whistle a name. The app can emit the whistle by entering the name in the Emit entry field in the main screen; it will interpolate between the given frequency values when it generates the voltage samples to emit (voltage sampling is 48000 per second for most tablets). Your whistle will be kept in a database which will be reloaded the next time you use the app and which can be exported to a file that can be sent remotely.</p>
  <p>To use the editor in DC and emit a new whistle:</p>
  <ol>
  <li>open the app (the first time, you need to allow a few permissions required by Android);</li>
  <li>select the WHISTLES top menu item;</li>
  <li>select a whistle in the list, such as the whistle named &quot;caret&quot; shown in the image;</li>
  <li>select the NEW button;</li>
  <li>enter the frequencies in this format &quot;[1]2000;&quot; where &quot;[1]&quot; is the rank of a value at a 40th of a second, &quot;2000&quot; is the frequency in Hz, and &quot;;&quot; is a separator, you can use approximate values at first and then edit them later;</li>
  <li>select the DRAW button to show the contour, a red line indicates a change in frequency which may be too steep; the voltages graph is drawn in the screen accessed with the VOLTAGES... button;</li>
  <li>enter a name, such as &quot;atest1&quot; (the &quot;a&quot; will have it listed at the top of the whistles list for easy access), no double-quotes;</li>
  <li>Back out of the editor to the whistles list screen;</li>
  <li>Back out of the whistles list to the main screen;</li>
  <li>Type &quot;atest1&quot; in the emit field, no double-quotes;</li>
  <li>Select the EMIT button to emit the whistle on the tablet speaker or a connected speaker if any.</li>
  </ol>
  <p><a href="https://i.sstatic.net/2GWKZ.png" rel="nofollow noreferrer"><img src="https://i.sstatic.net/2GWKZ.png" alt="enter image description here" /></a></p>
  
Answers.ContentLicense: CC BY-SA 4.0
Answers.CreationDate: 2022-07-22T15:41:30.527Z
Answers.LastActivityDate: 2022-08-09T12:48:50.127Z
Answers.LastEditDate: 2022-08-09T12:48:50.127Z
Answers.UserDisplayName: sm1
Answers.Body: <p>If you consider that for a signal</p>
  <p>s(t) = sin(phi(t))</p>
  <p>the frequency is</p>
  <p>f(t) = 1/(2pi) d/dt phi(t)</p>
  <p>then given a desired frequency function f(t),
  you construct first a phase function</p>
  <p>phi(t) = 2pi \int_0 ^t f(x) dx</p>
  <p>which you use in your phasor: sin(x), cos(x), exp(ix)</p>
  <p>Example:</p>
  <p>f(t) = f0 + (f1-f0) * t # linear FM</p>
  <p>phi(t) = 2pi * (f0 * t +(f1-f0) * t^2) = 2pi * (f0+(f1-f0)/2 * t) * t)</p>
  <p>Note: the integration explains the factor 2 in (f1-f0)/2</p>
  <p>Edit: I did a small Matlab script to visualize better what the answer is about.</p>
  <pre><code>    %signal generation
      %
      % sketch frequency
      u=[0.1,1000
      0.2,4000
      0.3,1500
      0.4,5000];
      %
      % interpolate
      fs=24000;
      T=(0:1/fs:0.5)';
      v=interp1(u(:,1),u(:,2),T,'pchip');
      %
      % truncate if necessary
      isel=(u(1,1)&lt;=T) &amp; (T&lt;= u(end,1));
      v=v(isel);
      t=T(isel);
      %
      % integrate to obtain phase
      om=2*pi*cumtrapz(v)/fs;
      %
      % generate amplitude function (here attenuate initial/final 
      % transient
      aa=ones(size(t)); 
      i1=(1:0.1*fs)';
      aa(i1)=aa(i1).*exp(-1/2*((i1-i1(end))/(0.03*fs)).^2);
      i2=length(t)+1-fliplr(1:0.1*fs)';
      aa(i2)=aa(i2).*exp(-1/2*((i2-i2(1))/(0.03*fs)).^2);
      %
      % generate signal
      s=aa.*sin(om);
      %
      % for visualisation add leading and trailing zeroes
      s=[zeros(0.1*fs,1);s;zeros(0.1*fs,1)];
      %
      % for visualization add noise
      s=s+0.01*randn(size(s));
      %%
      %visualize
      figure(1)
      subplot(211)
      plot(u(:,1),u(:,2),'o',t,v)
      subplot(212)
      spectrogram(s,hann(256),128,1024,fs,'yaxis');
      line(t*1000,v/1000,'color','k')
  </code></pre>
  <p>which generates
  <a href="https://i.sstatic.net/9VkMD.jpg" rel="nofollow noreferrer"><img src="https://i.sstatic.net/9VkMD.jpg" alt="enter image description here" /></a></p>
  <p>To address one of Dan Stowell concerns I added a amplitude weighting function that removes initial and final transients.</p>
  <p>Edit: to understand if simulated signal shows unwanted effects, it is best to inspect spectrogram. I did this in example to detect and remove initial and final transients. Readers with access to Matlab are invited to experiment with script.</p>
  
Answers.ContentLicense: CC BY-SA 4.0
Answers.CreationDate: 2022-07-22T15:50:07.917Z
Answers.Text: Please do **not** generate your own sinusiods using simple trig like this. It will very likely lead to problems such as aliasing, frequency/phase drift, etc. A particularly common problem is the lack of windowing (tapering) at the beginning/end of sinusoids, which can lead to broadband artefacts in both analysis experiments and experiments with animals. Use a well-designed software tool instead, as in @Noil's answer
Answers.UserDisplayName: Dan Stowell
Answers.ContentLicense: CC BY-SA 4.0
Answers.CreationDate: 2022-07-22T19:17:20.207Z
Answers.Text: I can NOT agree with Dan's comment on aliasing, frequency shift/phase drifts. I would advice to add an amplitude function that attenuates initial and final transients. It is really irrelevant how you synthesize your phasor, you always mast make sure that your transmitter  is not saturating.
Answers.UserDisplayName: WMXZ
Answers.ContentLicense: CC BY-SA 4.0
Answers.CreationDate: 2022-07-23T10:43:45.697Z
Answers.Text: We can agree to disagree, that's fine. However, implementation is not irrelevant when it can lead to artefacts. I emphasise that I've seen these problems actually happen, both in published papers and live software.
Answers.UserDisplayName: Dan Stowell
Answers.ContentLicense: CC BY-SA 4.0
Answers.CreationDate: 2022-07-23T19:05:49.683Z
Answers.Text: I added Matlab code and picture to show the process
Answers.UserDisplayName: WMXZ
Answers.ContentLicense: CC BY-SA 4.0
Answers.CreationDate: 2022-07-27T14:02:46.043Z
Answers.Text: Would be enough to check the spectrogram to make sure the simulation does not generate unexpected artefacts?
Answers.UserDisplayName: Marcelo Araya-Salas
Answers.ContentLicense: CC BY-SA 4.0
Answers.CreationDate: 2022-07-27T15:03:23.420Z
Answers.Text: @Marcelo, yes, I edited my answer accordingly.
Answers.UserDisplayName: WMXZ
Answers.ContentLicense: CC BY-SA 4.0
Answers.CreationDate: 2022-07-21T08:00:43.187Z
Answers.LastActivityDate: 2022-07-27T15:02:34.790Z
Answers.LastEditDate: 2022-07-27T15:02:34.790Z
Answers.UserDisplayName: WMXZ
Body: <p>I'd like to synthesise a series of bat social-call like sounds (that look 'wavy' on the spectrogram, (see schematic below). I'm looking to test my acoustic analyses with synthetic audio
  , and being able to generate sounds with arbitrary frequency modulations is important.</p>
  <p><a href="https://i.sstatic.net/8AlXz.png" rel="noreferrer"><img src="https://i.sstatic.net/8AlXz.png" alt="enter image description here" /></a></p>
  <p>I know how to make other synthetic sounds like pure tones, and various sweeps (linear, hyperbolic, log) using <code>scipy.signal.chirp</code> in python, and its analogs in MATLAB. Essentially, the input needs to be the frequency at a given time/sample, and the output needs to be a waveform that results in that 'frequency-profile'.</p>
  <p>Can someone point me to a formula to generate arbitrary frequency modulated sounds, or even an open-source tool to generate such sounds?</p>
  
Tags: <analysis><modelling>
Title: How do I synthesise an arbitrary frequency-modulated sound?
ThreadText: # How do I synthesise an arbitrary frequency-modulated sound?
  
  (Asked by: username_0 on 2022-07-21)
  
  I'd like to synthesise a series of bat social-call like sounds (that look 'wavy' on the spectrogram, (see schematic below). I'm looking to test my acoustic analyses with synthetic audio
  , and being able to generate sounds with arbitrary frequency modulations is important.
  
  [![enter image description here](https://i.sstatic.net/8AlXz.png)](https://i.sstatic.net/8AlXz.png)
  
  I know how to make other synthetic sounds like pure tones, and various sweeps (linear, hyperbolic, log) using `scipy.signal.chirp` in python, and its analogs in MATLAB. Essentially, the input needs to be the frequency at a given time/sample, and the output needs to be a waveform that results in that 'frequency-profile'.
  
  Can someone point me to a formula to generate arbitrary frequency modulated sounds, or even an open-source tool to generate such sounds?
  
  **Tags:** analysis, modelling
  
  
  ---
  
  ## 3 answers
  
  ### Answer by username_4 on 2022-07-21. Score: 7 | Accepted answer
  
  If you consider that for a signal
  s(t) = sin(phi(t))
  the frequency is
  f(t) = 1/(2pi) d/dt phi(t)
  then given a desired frequency function f(t),
  you construct first a phase function
  phi(t) = 2pi \int_0 ^t f(x) dx
  which you use in your phasor: sin(x), cos(x), exp(ix)
  Example:
  f(t) = f0 + (f1-f0) * t # linear FM
  phi(t) = 2pi * (f0 * t +(f1-f0) * t^2) = 2pi * (f0+(f1-f0)/2 * t) * t)
  Note: the integration explains the factor 2 in (f1-f0)/2
  Edit: I did a small Matlab script to visualize better what the answer is about.
      %signal generation
      %
      % sketch frequency
      u=[0.1,1000
      0.2,4000
      0.3,1500
      0.4,5000];
      %
      % interpolate
      fs=24000;
      T=(0:1/fs:0.5)';
      v=interp1(u(:,1),u(:,2),T,'pchip');
      %
      % truncate if necessary
      isel=(u(1,1)<=T) & (T<= u(end,1));
      v=v(isel);
      t=T(isel);
      %
      % integrate to obtain phase
      om=2*pi*cumtrapz(v)/fs;
      %
      % generate amplitude function (here attenuate initial/final 
      % transient
      aa=ones(size(t)); 
      i1=(1:0.1*fs)';
      aa(i1)=aa(i1).*exp(-1/2*((i1-i1(end))/(0.03*fs)).^2);
      i2=length(t)+1-fliplr(1:0.1*fs)';
      aa(i2)=aa(i2).*exp(-1/2*((i2-i2(1))/(0.03*fs)).^2);
      %
      % generate signal
      s=aa.*sin(om);
      %
      % for visualisation add leading and trailing zeroes
      s=[zeros(0.1*fs,1);s;zeros(0.1*fs,1)];
      %
      % for visualization add noise
      s=s+0.01*randn(size(s));
      %%
      %visualize
      figure(1)
      subplot(211)
      plot(u(:,1),u(:,2),'o',t,v)
      subplot(212)
      spectrogram(s,hann(256),128,1024,fs,'yaxis');
      line(t*1000,v/1000,'color','k')
  
  which generates
  
  To address one of username_2 concerns I added a amplitude weighting function that removes initial and final transients.
  Edit: to understand if simulated signal shows unwanted effects, it is best to inspect spectrogram. I did this in example to detect and remove initial and final transients. Readers with access to Matlab are invited to experiment with script.
  
  > **Comments:**
  > **username_2**: Please do **not** generate your own sinusiods using simple trig like this. It will very likely lead to problems such as aliasing, frequency/phase drift, etc. A particularly common problem is the lack of windowing (tapering) at the beginning/end of sinusoids, which can lead to broadband artefacts in both analysis experiments and experiments with animals. Use a well-designed software tool instead, as in @username_1's answer  
  > **username_4**: I can NOT agree with Dan's comment on aliasing, frequency shift/phase drifts. I would advice to add an amplitude function that attenuates initial and final transients. It is really irrelevant how you synthesize your phasor, you always mast make sure that your transmitter  is not saturating.  
  > **username_2**: We can agree to disagree, that's fine. However, implementation is not irrelevant when it can lead to artefacts. I emphasise that I've seen these problems actually happen, both in published papers and live software.  
  > **username_4**: I added Matlab code and picture to show the process  
  > **username_5**: Would be enough to check the spectrogram to make sure the simulation does not generate unexpected artefacts?  
  > **username_4**: @Marcelo, yes, I edited my answer accordingly.  
  
  ---
  
  ### Answer by username_1 on 2022-07-21. Score: 7
  
  An alternative would be to draw the pitch over time —as you did it in your example picture— and generate the associated sound. This can be straight-forward sometimes, depending of your constraints.
  
  You can do this easily if you are familiar with [Max](https://cycling74.com/downloads) or [Pure Data](https://puredata.info/) programming languages (draw the pitch, select the speed it should be read, link the drawing to the frequency of the sinusoidal generator).
  
  You could also use a more-friendly-interface software such as [Spear](https://www.klingbeil.com/spear/); it says "Features include: pencil tool for drawing":
  
  [![enter image description here](https://i.sstatic.net/ruHPD.png)](https://i.sstatic.net/ruHPD.png)
  (picture from [Klingbeil 2005](https://www.semanticscholar.org/paper/Software-for-spectral-Analysis%2C-Editing%2C-and-Klingbeil/505d336033e290066c8cf114194a5c530f1895e4))
  
  > **Comments:**
  > **username_2**: This is a great answer. As well as Max & Pure Data, I would recommend to add **SuperCollider** (my favourite). I would expect there to be a good Python library too, but no - there are a few options but none of them very mature/dependable  
  
  ---
  
  ### Answer by username_3 on 2022-07-22. Score: 3
  
  Edited 2022-8-9: the bug is fixed in the new release published yesterday August 8, 2022, version 39.
  
  Edited 2022-7-27: a bug discovered after posting this answer prevents a newly created whistle to not be stored properly in the persistent database and therefore the new whistle frequencies are lost when the app is closed; the bug is getting fixed and in the mean time please use the editor while taking this into consideration; a new version will be released when the bug is fixed.
  
  Original post:
  Here's an open source tool to generate such sounds, the source code is in gitlab: DC Dolphin Communicator, free for Android, from <https://play.google.com/store/apps/details?id=sm.app.dc> - I wrote it. It may do what you need, although the app is also designed for whistle recognition. It is best used on a tablet instead of a phone.
  
  It has an editor that lets you build whistles within a ~0.5 kHz to 11 kHz range. You need to defined the frequency values in Hz at each 40th of a second. You give the whistle a name. The app can emit the whistle by entering the name in the Emit entry field in the main screen; it will interpolate between the given frequency values when it generates the voltage samples to emit (voltage sampling is 48000 per second for most tablets). Your whistle will be kept in a database which will be reloaded the next time you use the app and which can be exported to a file that can be sent remotely.
  
  To use the editor in DC and emit a new whistle:
  
  1. open the app (the first time, you need to allow a few permissions required by Android);
  2. select the WHISTLES top menu item;
  3. select a whistle in the list, such as the whistle named "caret" shown in the image;
  4. select the NEW button;
  5. enter the frequencies in this format "[1]2000;" where "[1]" is the rank of a value at a 40th of a second, "2000" is the frequency in Hz, and ";" is a separator, you can use approximate values at first and then edit them later;
  6. select the DRAW button to show the contour, a red line indicates a change in frequency which may be too steep; the voltages graph is drawn in the screen accessed with the VOLTAGES... button;
  7. enter a name, such as "atest1" (the "a" will have it listed at the top of the whistles list for easy access), no double-quotes;
  8. Back out of the editor to the whistles list screen;
  9. Back out of the whistles list to the main screen;
  10. Type "atest1" in the emit field, no double-quotes;
  11. Select the EMIT button to emit the whistle on the tablet speaker or a connected speaker if any.
  
  [![enter image description here](https://i.sstatic.net/2GWKZ.png)](https://i.sstatic.net/2GWKZ.png)
  
  
  ---
  
  