Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Note Synthesis, Harmonics (Violin, Piano, Guitar, Bass), Frequencies, MIDI [closed]

I want to find, how notes were built. Example for a Instrument (Violin or Piano), The Note LA4 (A4) has main (or central) frequency FC at 440Hz with a Specific Amplitude AC, but also it must has other frequencies (harmonics?) FH with other amplitudes AH.

The Harmonics have other frequencies that are dependant of Main Frequency with amplitudes (almost) less than the amplitude of Main Frequency.

Forming (building) Notes

I want to know how is formed (established) the notes (No time is considered).

Example: A4 = AC(FC) + AH1(FH1)+ AH2(FH2) + AH3(FH3) + AH4(FH4)....AHn(FHn) Maybe, FH1 = 2*FC, FH2 = 3*FC, FH3 = 4*FC, and so on....

Comparing between instruments (Violin and Piano)

For Piano, The Note LA4 (A4) has main frequency FC at 440Hz, and Maybe, FC(Piano) = FC(Violin), FH1(Piano) = FH1(Violin), FH2(Piano) = FH2(Violin), and so on....

But, AC(Piano) != AC(Violin), AH1(Piano) != AH1(Violin), AH2(Piano) != AH2(Violin), and so on....

Example of my question is: http://www.phys.unsw.edu.au/jw/sound.spectrum.html

I want to play this notes avoiding MIDI format, this can be implemented in Java/C# (or other language programming) Later, and more control of my sounds.

Thank you.

Ana

like image 713
Anita Avatar asked May 22 '12 13:05

Anita


2 Answers

I have this...

    int iTone = 40;   //Tone to be interpreted
    iSmplRate = 32000;  //Sample Rate
    int NumBytesPerSample = 16;  // 8 or 16
    int NumChannels = 2;  //1 Mono, 2 Stereo
    double Duration = 6.5; //Seconds performing
    Short sAmplit = 1200;
    int iNumSmpl = (int)(SampleRate*Duration);
    NumTotalBytes = (int)(SampleRate*Duration*NumBytesPerSample*NumChannels);
    ByteBuffer bbWav = ByteBuffer.allocate(NumTotalBytes);


    double dMaxInstr = (double)Short.MIN_VALUE;
    double dMinInstr = (double)Short.MAX_VALUE;


    //Amplitude for violin's armonics 
    double[] violAmps = {1.0, 0.286699025, 0.150079537, 0.042909002, 
                        0.203797365, 0.229228698, 0.156931925, 
                        0.115470898, 0.0, 0.097401803, 0.087653465, 
                        0.052331036, 0.052922462, 0.038850593, 
                        0.053554676, 0.053697434, 0.022270261, 
                        0.013072562, 0.008585879, 0.005771505,
                        0.004343925, 0.002141371, 0.005343231, 
                        0.000530244, 0.004711017, 0.009014153};

    //Amplitude for piano's armonics 
    double[] pianAmps = {1.0, 0.399064778, 0.229404484, 0.151836061,
                        0.196754229, 0.093742264, 0.060871957,
                        0.138605419, 0.010535002, 0.071021868,
                        0.029954614, 0.051299684, 0.055948288,
                        0.066208224, 0.010067391, 0.00753679,
                        0.008196947, 0.012955577, 0.007316738,
                        0.006216476, 0.005116215, 0.006243983,
                        0.002860679, 0.002558108, 0.0, 0.001650392};
    double[] operator = {1.0};
    if (instrument.equals("violin")) {
      operator = violAmps;
    }
    if (instrument.equals("piano")) {
      operator = pianAmps;
    }
    double dFreq = 440.0*Math.pow(2.0, (iTone-69)/12.0;

    double dFreqRel = iSmplRate/dFreq;
    Integer iSampleInstrument = null;
    double PI2 = 2*Math.PI;

    int[] iSamplesInstr = new int[iNumSmpl];
    for (int i = 0;i < iNumSmpl; i++) {
      Double Angle = i*PI2/dFreqRel;
      Double dInstrument = 0.0;
      for (int a = 1; a <=operator.length; a++) {
        dInstrument += operator[a-1]*Math.sin((double)a*Angle);
      }

      dMaxInstr = (dInstrument>dMaxInstr)?dInstrument:dMaxInstr;
      dMinInstr = (dInstrument<dMinInstr)?dInstrument:dMinInstr;

      iSampleInstrument = (int)(sAmplit*dInstrument);

      if (instrument.equals("violin")) {
        double FreqEnvV = iSmplRate/6.0;
        double FracEnvV = 35.0;
        double dEnvViolin = sAmplit*DStepperExt(Math.sin(1.0*i*PI2/FreqEnvV),4)/FracEnvV;
        iSampleInstrument = (int)(iSampleInstrument+dEnvViolin);
      }
      if (instrument.equals("piano")) {
        double FracEnvP = 8.0/10.0;
        double AngP = (double)i/(iSmplRate*FracEnvP);
        double EnvPiano = 1.0/Math.exp(AngP);
        iSampleInstrument = (int)(iSampleInstrument*EnvPiano);
      }
      dMxSmplInstr = (iSampleInstrument>dMxSmplInstr)?iSampleInstrument:dMxSmplInstr;
      dMnSmplInstr = (iSampleInstrument<dMnSmplInstr)?iSampleInstrument:dMnSmplInstr;
      iSamplesInstr[i] = iSampleInstrument;
    }

    double dMaxAbs = 
            (Math.abs(dMaxInstr)>Math.abs(dMinInstr))?Math.abs(dMaxInstr):Math.abs(dMinInstr);
    double dMxAbsSmpl = 
            (Math.abs(dMxSmplInstr)>Math.abs(dMnSmplInstr))?Math.abs(dMxSmplInstr):Math.abs(dMnSmplInstr);
    double dNormal = 1.0;
    if (dMxAbsSmpl > 32768.0) {
      dNormal = 32768.0/dMxAbsSmpl;
    }

    for (int i = 0;i < iNumSmpl; i++) {
      short sSampleInst = (short)(iSamplesInstr[i]*dNormal);
      try {
        if (iNumByteSmpl == 2) {
          bbWav.put((byte)((sSampleInst >> 0) & 0xFF));
          bbWav.put((byte)((sSampleInst >> 8) & 0xFF));
          if (iNumChnnls == 2) {
            bbWav.put((byte)((sSampleInst >> 0) & 0xFF));
            bbWav.put((byte)((sSampleInst >> 8) & 0xFF));
          }
        } else {
          byte ByteSample = (byte)((sSampleInst >> 8) & 0xFF);
          short ShrtSample = (short)(ByteSample & 0xFF);
          ShrtSample += 128;
          bbWav.put((byte)(ShrtSample & 0xFF));
          if (iNumChnnls == 2) {
            bbWav.put((byte)(ShrtSample & 0xFF));
          }
        }
      } catch (Exception e) {
        System.out.println(e.getMessage());
      }

This code is used in Violin instrument:

  private Double DStepperExt(Double Val, Integer Steps) {
    //Return a value inside in range defined by step
    //Divide [-1.0,1.0]/(Steps-1), retorning the value according to the range
    //The value must be between 0.0 and 1.0
    if (Steps <= 0.0) { 
      return 0.0;
    }
    if (Val != -1.0 && Val != 1.0) {
      Val = Val - Val.intValue();
    }
    Double sDouble = new Double(Steps-1);
    Double bdStep = 2.0/sDouble;
    Double bdRef = bdStep/2.0;
    bdRef = bdRef - 1.0;
    Double bdInit = -1.0;

    Double bdRet = null;
    for (int c = 0; c<=sDouble;c++) {
      if (Val < bdRef) {
        bdRet = bdInit;
        break;
      } else {
        bdInit = bdInit+bdStep;
        bdRef = bdRef+bdStep;
      }
    }
    return Math.min(bdRet.doubleValue(),1.0);
  }

Try this code, my sound isn't perfect but is very similar.

like image 74
joseluisbz Avatar answered Oct 04 '22 02:10

joseluisbz


Be aware that what you are undertaking is a huge task. If your goal is to create your own synthesizer that can sound like a piano, violin, etc by adding together harmonics with specific amplitudes then it is incredibly difficult to create a sound that is in any way realistic. The harmonics of an acoustic instrument vary over time in a complex fashion. As guidot notes, the attack and delay parts of sound will be very different. If you try to measure the relative amplitudes of a real instrument at a number of points over time and then synthesise the sinusoids then the best you will achieve is something that will sound like a child's toy.

If that's what you want to do then you will need to analyse the spectrum over time of the sounds you want to emulate. The easiest way I would suggest is using something like Matlab, Octave or Scipy. If you want visualisations then try Sonic Visualiser or Marsyas.

If however you want to create realistic playback then you have two options. One is to use Wavetable synthesis, which is how many cheap synthesisers (especially ones on PC soundcards) work. The other is to look into Physical Modelling Synthesis which simulates the physics of an instrument to create realistic sounds.

like image 43
the_mandrill Avatar answered Oct 04 '22 03:10

the_mandrill