WAV file - summary in a row of sine waves... need help

  • (4 Pages)
  • +
  • 1
  • 2
  • 3
  • Last »

55 Replies - 3807 Views - Last Post: 07 April 2021 - 11:43 AM Rate Topic: ****- 3 Votes

#1 danielhc   User is offline

  • New D.I.C Head

Reputation: 0
  • View blog
  • Posts: 28
  • Joined: 26-February 21

WAV file - summary in a row of sine waves... need help

Posted 11 March 2021 - 12:12 PM

Hello,

I'm trying to do some project at C because I'm new at coding,

I making a Decoder and Encoder for Morse code.
I use morse configuration by user free choice of: frequency[Hz] of dot, frequency[Hz] of dash, time of dot[ms], time of dash[ms], and delay between dot and dash[ms].

the user writing the configuration and the text, the text converted to morse code.
now I want to make an output WAV file of the morse code text (dot and dash) with the user configuration (part of the WAV file).

I tried a lot of examples from the internet and GitHub and I didn't succeed...

this part of my code:
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h> 
#include <stdlib.h> 
#include "config.h"
#include <conio.h>

int transmit()
{
//---------------------------------Setting & Variables-----------------------------------------//
	system("cls");//clear screen
	//char T[25] = { '\0' }; //transmit user input variable 
	char str[25],str1[100]; //str contain the text from user, str1 contain the morse convert
	int i = 0, j = 0;
	int count = 0;
	//unsigned int frequancy_dash, frequancy_dot, dash_time, dot_time, delay_dd;
	//int index = 0,c;
	//char buffer[256]; //to read from config.txt
	struct Config config; //create stuck type Config named config
	int configmain(void);
//-------------------------------Read Configuration file---------------------------------------//
	FILE* fp;
	fp = fopen("config.txt", "r");
	if (fp == NULL) //check if the file exist if not --> go to config function to create new config.txt file
	{
		config();
	}
	else //if config.txt empty --> go to config function to create new config.txt file
	{
		fseek(fp, 0, SEEK_END);//start from 0 location to the end of the file
		if (ftell(fp) == 0) //check if the file empty
		{
			config();
		}
	}
	rewind(fp);//back to file start

	while (fgets(buffer, sizeof(buffer), fp)) //read all config.txt
	{
		puts(buffer);
	}
	
	rewind(fp);//back to file start
	while (fgets(buffer, sizeof(buffer), fp))
	{
		if (!parse(buffer))
		{
			fclose(fp);
			return 0;
		}
	}
	gets(enter);//recive the 'Enter' pressing from user 

	fclose(fp);

*/

//new config v1.2//
//-------------------------------Read Configuration file---------------------------------------//
	FILE* fp;
	fp = fopen("config.txt", "r");
	if (fp == NULL) //check if the file exist if not --> go to config function to create new config.txt file
	{
		printf("error reading config.txt - Press Enter\n"); //UI error message
		system("cls"); //clear screen
		configmain();
		return 1;
	}	
	system("cls"); //clear screen

//--------------------------------Display configuration----------------------------------------//
	config_read(&config, "config.txt"); //read config.txt file
	printf("Exists configuration:\n"); //UI message
	printf("Freq dot is %i\n", config.freq_dot); // UI Display what is in config file
	printf("Freq dash is %i\n", config.freq_dash);
	printf("Time dot is %i\n", config.time_dot);
	printf("Time dash is %i\n", config.time_dash);
	printf("Delay %i\n", config.delay);

//-----------------------------------Recive user text------------------------------------------//
	int morse(); //define morse function
	morse(str,str1); //convert string to morse


        //WAV_morse_create(str1) // <-------------------[[[here i don't know what to do... i dont have this function its only for example ]]]






ill glad for your help.

Is This A Good Question/Topic? 0
  • +

Replies To: WAV file - summary in a row of sine waves... need help

#2 jimblumberg   User is offline

  • member icon

Reputation: 5904
  • View blog
  • Posts: 17,906
  • Joined: 25-December 09

Re: WAV file - summary in a row of sine waves... need help

Posted 11 March 2021 - 01:45 PM

Also posted here.
Was This Post Helpful? 2
  • +
  • -

#3 Skydiver   User is offline

  • Code herder
  • member icon

Reputation: 7733
  • View blog
  • Posts: 25,850
  • Joined: 05-May 12

Re: WAV file - summary in a row of sine waves... need help

Posted 11 March 2021 - 02:32 PM

This was the first hit on Google when I searched for "how to create a wav file in C":
Making WAV files from C programs

For morse code, you don't really need a sine wav. All you need are pulse waves composed of a tone and silence. It's just a matter of varying the lengths of the tones and silences.
Was This Post Helpful? 0
  • +
  • -

#4 danielhc   User is offline

  • New D.I.C Head

Reputation: 0
  • View blog
  • Posts: 28
  • Joined: 26-February 21

Re: WAV file - summary in a row of sine waves... need help

Posted 12 March 2021 - 01:13 AM

yes I thought about pulse waves but I didn't find any example with pulse wave, how I create one?

This post has been edited by Skydiver: 12 March 2021 - 06:29 AM
Reason for edit:: Removed unnecessary quote. No need to quote the post above yours.

Was This Post Helpful? 0
  • +
  • -

#5 Skydiver   User is offline

  • Code herder
  • member icon

Reputation: 7733
  • View blog
  • Posts: 25,850
  • Joined: 05-May 12

Re: WAV file - summary in a row of sine waves... need help

Posted 12 March 2021 - 06:30 AM

A pulse wave simply has high and low values. It's not like a sine wave where the values follow a sine function. Given that a pulse wave has only high and low values, set high values for the duration when you want a sound to be made, and set low values for the silences.
Was This Post Helpful? 0
  • +
  • -

#6 finetunewithhammer   User is offline

  • D.I.C Head

Reputation: 17
  • View blog
  • Posts: 86
  • Joined: 05-February 21

Re: WAV file - summary in a row of sine waves... need help

Posted 12 March 2021 - 09:57 AM

Read some document explaining the format of a WAV file. There are three consecutive chunks, containing information about the specifics like sample rate, channel count and file length. These need to be formatted exactly as specified. Getting to know the file format is your first hurdle.

Now you need to generate the sound. The sample rate tells you how many times you need a reading from the signal. Varying the signal between a high and low state plays a sound. If this variation is smooth the sound is a clean smooth tone. To produce a certain frequency, you need the signal to oscillate every sample span of sampleRate/toneFrequency. That is within the span of the amount of samples indicated by that ratio.

To get a smooth tone, chop the current sample location (time) into segments of sampleRate/toneFrequency units. For a sample rate of 22050 Hz and a tone of 600 Hz you need to scale approximately each 37th sample from a range 0..~36 to 0..2*PI.
Get the sin() of this scaled range. This results in a signal with values between ]-1..1[ oscillating at toneFrequnecy.
Scale this signal up by multiplying it with 2^15 for a 16 bit sample. This results in values between -32768..32768 These are the value ranges of 16bit integers.
You can/should multiply this by say 0.5 to lower the volume of the signal.

Thirdly you need to produce the desired sounds (and silences) from the input file as you specified. This is the third problem.
Concentrate on one of these at a time. You need to do them in order. Start here: https://en.wikipedia.org/wiki/WAV
Was This Post Helpful? 0
  • +
  • -

#7 Skydiver   User is offline

  • Code herder
  • member icon

Reputation: 7733
  • View blog
  • Posts: 25,850
  • Joined: 05-May 12

Re: WAV file - summary in a row of sine waves... need help

Posted 12 March 2021 - 03:57 PM

I'm kind of confused by this thread when put adjacent to our OP's older thread. In the older thread, the OP was already successfully generating sounds, and all he needed at that point was to figure out how to decode incoming sounds. Now in this thread, it looks like our OP has thrown away his old sound generation, and is now trying to generate sounds using WAV files.
Was This Post Helpful? 0
  • +
  • -

#8 danielhc   User is offline

  • New D.I.C Head

Reputation: 0
  • View blog
  • Posts: 28
  • Joined: 26-February 21

Re: WAV file - summary in a row of sine waves... need help

Posted 13 March 2021 - 12:27 AM

Yes, i did it before with Beeps windows lib but its isn't good for fftw and the frequency isn't accurate. Now i use WAV file and i read, write into external file the user configuration. All this change was for easy fftw usage.

This post has been edited by Skydiver: 13 March 2021 - 07:06 AM
Reason for edit:: Removed unnecessary quote. There is no need to quote the post above yours.

Was This Post Helpful? 0
  • +
  • -

#9 Skydiver   User is offline

  • Code herder
  • member icon

Reputation: 7733
  • View blog
  • Posts: 25,850
  • Joined: 05-May 12

Re: WAV file - summary in a row of sine waves... need help

Posted 13 March 2021 - 07:19 AM

There is no need to quote the post above yours. Just use the big Reply button or the Fast Reply area.

I think you need to step back a little and tell us what you are trying to accomplish and why. The reason I ask is because you had originally introduced yourself as a beginner in C. One of the common assignments/projects given to C learners is to convert plain text to Morse code. Often that assignment only requires that dots, dashes, and spaces be printed out. For extra credit, some teachers will ask for converting an input of dots, dashes, and spaces back to plain text.

I took your wanting to be able to actually emit the sounds, and also be able to listen to the sounds as something you were doing to get extra extra extra credit, or at least make your work stand out from that of your classmates.

Now that you are talking about using FFTW, I feel like there is something else at here, but I can't put my finger on it. In my mind, you don't need FFTs to generate the WAV file. AMD to decode Morse from the WAV file, you also don't need FFTs -- just need to implement a simple band pass filter and do a statistical run to figure out what the maximum duration of a dot is.

Are you an intern somewhere learning C and then tasked with interfacing with an IoT device that can and receive Morse code?
Was This Post Helpful? 0
  • +
  • -

#10 danielhc   User is offline

  • New D.I.C Head

Reputation: 0
  • View blog
  • Posts: 28
  • Joined: 26-February 21

Re: WAV file - summary in a row of sine waves... need help

Posted 13 March 2021 - 12:46 PM

I'm trying to make morse code decoder and encoder in C language,

this is the WAV file that I use but I receive bad signals and a lot of noise:

str1 is the array of morse message (dots and dashes)

#define _CRT_SECURE_NO_WARNINGS // To ingore VisualStudio C language errors
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <memory.h>
#include "config.h"//call config functions


#define SAMPLE_RATE 22050
#define WAV_LEN (SAMPLE_RATE*20)
#define M_PI       3.14159265358979323846   // pi

int pos_in_message, pos_in_symbol;
double phase = 0.0;

void generate_sample(int16_t o[2],char str1[100])
{
    struct Config config; //create stuck type Config named config
    int configmain(void);
    config_read(&config, "config.txt"); //read config.txt file

    int symbol_len, symbol_freq, symbol_total_len;

    int dot_len = config.time_dot;  // Milliseconds
    int dot_total_len = config.time_dot+100;  // Milliseconds
    int dot_freq = config.freq_dot;  // Hz

    int dash_len = config.time_dash;  // Milliseconds
    int dash_total_len = config.time_dash+100;  // Milliseconds
    int dash_freq = config.freq_dash;  // Hz

    int space_len = 0;    // Milliseconds
    int space_total_len = (config.time_dot + config.time_dash)/2;  // Milliseconds
    int space_freq = (config.freq_dot + config.freq_dash)/2;  // Hz


    switch(str1[pos_in_message]) {
       case '.':
          symbol_len       = dot_len;
          symbol_freq      = dot_freq;
          symbol_total_len = dot_total_len;
          break;
       case '-':
          symbol_len       = dash_len;
          symbol_freq      = dash_freq;
          symbol_total_len = dash_total_len;
          break;
       default:
          symbol_len       = space_len;
          symbol_freq      = space_freq;
          symbol_total_len = space_total_len;
          break;
    }
    symbol_len       = symbol_len * SAMPLE_RATE / 1000;  // Convert milliseconds to samples
    symbol_total_len = symbol_total_len * SAMPLE_RATE / 1000;  // Convert milliseconds to samples

    if(pos_in_symbol < symbol_len)
    {
        o[0] = sin(phase*symbol_freq)*10000;
    } else {
       o[0] = 0;
    }
    o[0] += rand()%40000-10000;
    o[1] = o[0];

    if(pos_in_symbol < symbol_total_len)
    {
       pos_in_symbol++;
    } else {
       pos_in_symbol = 0;
       pos_in_message++;
       if(str1[pos_in_message] == '\0')
          pos_in_message = 0;
    }
    phase += (2*M_PI)/SAMPLE_RATE;
    if(phase >= 2*M_PI)
       phase -= 2*M_PI;
}

////////////////////////////////////////////////////////////////////////
struct WaveFileHeader {
  uint8_t  chunkID[4];
  uint8_t  chunkSize[4];
  uint8_t  chunkFormat[4];

  uint8_t  subchunk1ID[4];
  uint8_t  subchunk1Size[4];
  uint8_t  audioFormat[2];
  uint8_t  numChannels[2];
  uint8_t  sampleRate[4];
  uint8_t  byteRate[4];
  uint8_t  blockAlign[2];
  uint8_t  bitsPerSample[2];

  uint8_t  subchunk2ID[4];
  uint8_t  subchunk2Size[4];
};


void intToU4(uint8_t *d, int val)
{
   d[0] = val;
   d[1] = val>>8;
   d[2] = val>>16;
   d[3] = val>>24;
}

void intToU2(uint8_t *d, int val)
{
   d[0] = val&0xFF;
   d[1] = val>>8;
}

int output_header(FILE *f, int samples_to_generate)
{
   struct WaveFileHeader header;

   memcpy(header.chunkID,       "RIFF",4);
   intToU4(header.chunkSize,     36 + samples_to_generate*4);
   memcpy(header.chunkFormat,    "WAVE",4);

   memcpy(header.subchunk1ID,   "fmt ",4);
   intToU4(header.subchunk1Size, 16);
   intToU2(header.audioFormat,   1);
   intToU2(header.numChannels,   2);
   intToU4(header.sampleRate,    44100);
   intToU4(header.byteRate,      44100*4);
   intToU2(header.blockAlign,    4);
   intToU2(header.bitsPerSample, 16);
   memcpy(header.subchunk2ID,   "data", 4);
   intToU4(header.subchunk2Size, samples_to_generate*4);
   if(fwrite(&header, sizeof(header), 1, f) != 1) {
      return 0;
   }
   return 1;
}
int write_sample(FILE *f, int16_t samples[2]) {
   uint8_t o[4];
   o[0] = samples[0];
   o[1] = samples[0]>>8;
   o[2] = samples[1];
   o[3] = samples[1]>>8;
   if(fwrite(o, sizeof(o), 1, f) != 1) 
     return 0;
   return 1;
}

int morse_tx(char str1[100])
{
   FILE *f;
   int16_t samples[2];
   f = fopen("out.wav","w");
   if(f == NULL)
   {
     fprintf(stderr, "Unable to open output file\n");
     return 0;
   } 
   output_header(f, WAV_LEN);
   for(int i = 0; i < WAV_LEN; i++) {
       generate_sample(samples,str1);
       write_sample(f, samples);
   }
   fclose(f);
   return 0;
}


Was This Post Helpful? 0
  • +
  • -

#11 finetunewithhammer   User is offline

  • D.I.C Head

Reputation: 17
  • View blog
  • Posts: 86
  • Joined: 05-February 21

Re: WAV file - summary in a row of sine waves... need help

Posted 13 March 2021 - 04:12 PM

To get less noise try this:
o[0] += (int) (((double)rand()/(double)RAND_MAX - 0.5) * (double)rand()/(double)RAND_MAX * 2000)

instead of line 64.
Your noise generation produces values between [-10000..29000] at random, and uniformly distributed within that range. There is also no simple way to calibrate the level of noise.
In my example (double)rand()/(double)RAND_MAX produces a value between [0..1[
Then -0.5 modifies this to be [-0.5..0.5[
The second part (double)rand()/(double)RAND_MAX * 2000 produces a number in the range [0..2000[
Adjust that last constant '2000' to reflect the magnitude of noise you wish to have.
Multiplying the first random value with the second can produce numbers in the range [-1000..1000[ it is however likely that the numbers will be in the middle of this range. To get a value in the extremes, the first number would have to be in either extreme and the second one near the larger possible values.
Was This Post Helpful? 0
  • +
  • -

#12 danielhc   User is offline

  • New D.I.C Head

Reputation: 0
  • View blog
  • Posts: 28
  • Joined: 26-February 21

Re: WAV file - summary in a row of sine waves... need help

Posted 14 March 2021 - 09:24 AM

I still receive noise/bad samples but I don't know why...
also, I don't understand why I receive not accurate frequency, I check it here:
https://academo.org/...ctrum-analyzer/

This post has been edited by Skydiver: 14 March 2021 - 09:46 AM
Reason for edit:: Removed unnecessary quote. There is no need to quote the post above yours.

Was This Post Helpful? 0
  • +
  • -

#13 Skydiver   User is offline

  • Code herder
  • member icon

Reputation: 7733
  • View blog
  • Posts: 25,850
  • Joined: 05-May 12

Re: WAV file - summary in a row of sine waves... need help

Posted 14 March 2021 - 09:49 AM

There is no need to quote the post above yours. Just use the big Reply button or the Fast Reply area.

My intuition is telling me that that fact that you are using random is why you are getting noise. Why are you even introducing a random element into the signal stream?

Any which way, show us your updated code so that we can follow along with what you are doing.
Was This Post Helpful? 0
  • +
  • -

#14 danielhc   User is offline

  • New D.I.C Head

Reputation: 0
  • View blog
  • Posts: 28
  • Joined: 26-February 21

Re: WAV file - summary in a row of sine waves... need help

Posted 14 March 2021 - 10:00 AM

the noise is no big issue, for now, the bigger issue is that I use a specific frequency but after the WAV file generated the frequency isn't what I choose...

#define _CRT_SECURE_NO_WARNINGS // To ingore VisualStudio C language errors
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <memory.h>
#include "config.h"//call config functions


#define SAMPLE_RATE 22050
#define WAV_LEN (SAMPLE_RATE*20)
#define M_PI       3.14159265358979323846   // pi

int pos_in_message, pos_in_symbol;
double phase = 0.0;

void generate_sample(int16_t o[2],char str1[100])
{
    struct Config config; //create stuck type Config named config
    int configmain(void);
    config_read(&config, "config.txt"); //read config.txt file

    int symbol_len, symbol_freq, symbol_total_len;

    int dot_len = config.time_dot;  // Milliseconds
    int dot_total_len = config.time_dot+100;  // Milliseconds
    int dot_freq = config.freq_dot;  // Hz

    int dash_len = config.time_dash;  // Milliseconds
    int dash_total_len = config.time_dash+100;  // Milliseconds
    int dash_freq = config.freq_dash;  // Hz

    int space_len = 0;    // Milliseconds
    int space_total_len = config.delay+100;  // Milliseconds
    int space_freq = config.delay;  // Hz


    switch(str1[pos_in_message])
    {
       case '.':
          symbol_len       = dot_len;
          symbol_freq      = dot_freq;
          symbol_total_len = dot_total_len;
          break;

       case '-':
          symbol_len       = dash_len;
          symbol_freq      = dash_freq;
          symbol_total_len = dash_total_len;
          break;

       default:
          symbol_len       = space_len;
          symbol_freq      = space_freq;
          symbol_total_len = space_total_len;
          break;
    }

    symbol_len       = symbol_len * SAMPLE_RATE / 1000;  // Convert milliseconds to samples
    symbol_total_len = symbol_total_len * SAMPLE_RATE / 1000;  // Convert milliseconds to samples

    if(pos_in_symbol < symbol_len)
    {
        o[0] = sin(phase*symbol_freq)*10000;
    } else 
    {
       o[0] = 0;
    }
    //o[0] += rand()%40000-10000;
    o[0] += (int)(((double)rand() / (double)RAND_MAX - 0.5) * (double)rand() / (double)RAND_MAX * 2000); // to reduce the noise was at the line above
    o[1] = o[0];

    if(pos_in_symbol < symbol_total_len)
    {
       pos_in_symbol++;
    } else 
    {
       pos_in_symbol = 0;
       pos_in_message++;
       if(str1[pos_in_message] == '\0')
          pos_in_message = 0;
    }
    phase += (2*M_PI)/SAMPLE_RATE;
    if(phase >= 2*M_PI)
       phase -= 2*M_PI;
}

////////////////////////////////////////////////////////////////////////
struct WaveFileHeader
{
  uint8_t  chunkID[4];
  uint8_t  chunkSize[4];
  uint8_t  chunkFormat[4];

  uint8_t  subchunk1ID[4];
  uint8_t  subchunk1Size[4];
  uint8_t  audioFormat[2];
  uint8_t  numChannels[2];
  uint8_t  sampleRate[4];
  uint8_t  byteRate[4];
  uint8_t  blockAlign[2];
  uint8_t  bitsPerSample[2];

  uint8_t  subchunk2ID[4];
  uint8_t  subchunk2Size[4];
};


void intToU4(uint8_t *d, int val)
{
   d[0] = val;
   d[1] = val>>8;
   d[2] = val>>16;
   d[3] = val>>24;
}

void intToU2(uint8_t *d, int val)
{
   d[0] = val&0xFF;
   d[1] = val>>8;
}

int output_header(FILE *f, int samples_to_generate)
{
   struct WaveFileHeader header;

   memcpy(header.chunkID,       "RIFF",4);
   intToU4(header.chunkSize,     36 + samples_to_generate*4);
   memcpy(header.chunkFormat,    "WAVE",4);

   memcpy(header.subchunk1ID,   "fmt ",4);
   intToU4(header.subchunk1Size, 16);
   intToU2(header.audioFormat,   1);
   intToU2(header.numChannels,   2);
   intToU4(header.sampleRate,    44100);
   intToU4(header.byteRate,      44100*4);
   intToU2(header.blockAlign,    4);
   intToU2(header.bitsPerSample, 16);
   memcpy(header.subchunk2ID,   "data", 4);
   intToU4(header.subchunk2Size, samples_to_generate*4);
   if(fwrite(&header, sizeof(header), 1, f) != 1)
   {
      return 0;
   }
   return 1;
}
int write_sample(FILE *f, int16_t samples[2])
{
   uint8_t o[4];
   o[0] = samples[0];
   o[1] = samples[0]>>8;
   o[2] = samples[1];
   o[3] = samples[1]>>8;
   if(fwrite(o, sizeof(o), 1, f) != 1) 
     return 0;
   return 1;
}

int morse_tx(char str1[100])
{
   FILE *f;
   int16_t samples[2];
   f = fopen("out.wav","w");
   if(f == NULL)
   {
     fprintf(stderr, "Unable to open output file\n");
     return 0;
   } 
   output_header(f, WAV_LEN);
   for(int i = 0; i < WAV_LEN; i++)
   {
       generate_sample(samples,str1);
       write_sample(f, samples);
   }
   fclose(f);
   return 0;
}




i config this parameters:
frequency_dot=6500
frequency_dash=1500
time_dot=1000
time_dash=800
delay=300

and the output that I receive:

https://ibb.co/2j4tdmR
Was This Post Helpful? 0
  • +
  • -

#15 finetunewithhammer   User is offline

  • D.I.C Head

Reputation: 17
  • View blog
  • Posts: 86
  • Joined: 05-February 21

Re: WAV file - summary in a row of sine waves... need help

Posted 14 March 2021 - 12:33 PM

You are not generating the frequency you think you are.
phase gets a value between 0..2*PI distributed over the entire span of 22050 samples, i.e. one second.
the signal generated is sin((x/(2*PI))*440), for a tone of 440Hz. this is not a smooth wave.

Use something similar as this code below, to get a smooth sine wave, at symbol_freq, in SAMPLE_RATE.
All new variables are doubles.
	//samples (in output) per oscillation (of signal of symbol_freq frequency)
	spo = (double) SAMPLE_RATE / (double) symbol_freq;
	//this is the same 'i' that is used in the for loop in main() pass it to generate_sample()
	time = (double) i;
	//current local sample, within group of samples for this oscillation
	//value is [0..spo[
	cls = ( time - spo * floor( time/spo ) );
	//signal x, value range of cls scaled to 2*PI
	sx = cls/spo*2*M_PI;
	//signal value in range ]-1..1]
	signal = sin(sx);
	//scaling the signal value to gain amplitude
	o[0] = (int) (signal * 5000.0);


Was This Post Helpful? 0
  • +
  • -

  • (4 Pages)
  • +
  • 1
  • 2
  • 3
  • Last »