C Write / Read Data From Binary File - c++

UPDATE
IBM HC-486 1995 11 12 228 Иванов IBM HC-476 1990 1 42 218 Васильев
So i kinda try to read two records. First one fits out well. Second looks bad.
I kinda fixed suggestions thanks a lot it helped to move forward. So for now i stuck on outputing two records.
Result is ->
mark = IBM HC-486 year = 1995 month = 11 day = 12 numroom = 228 lastname = Ивановmark = IBM HC-47 year = 6 month = 1990
day = 1 numroom = 42 lastname = 218mark = Васи� year = 6 month = 1990 day = 1 numroom = 42 lastname = �ьев
Making a binary file out of structs, attempting to print out all cointaining..
ONLY scanf/printf/FILE/struct
Here's a code...
Lab.h
#pragma once
void input();
void find();
int getdays(int year, int month);
void correction();
void print();
Lab.cpp
#include "Lab.h"
#include <stdio.h> //FILE
#include <iostream>
#include <conio.h> //getch
#include <windows.h>
#include <io.h>
struct Computer
{
wchar_t mark[11];
int year;
int month;
int day;
unsigned char numroom;
wchar_t lastname[20];
};
void input()
{
FILE *inputFile, *outputFile;
fopen_s(&outputFile, "output.dat", "wb");
fopen_s(&inputFile, "input.txt", "r");
Computer c;
while (fgetws(c.mark, 11, inputFile))
{
fscanf_s(inputFile, "%d", &c.year);
fscanf_s(inputFile, "%i", &c.month);
fscanf_s(inputFile, "%i", &c.day);
fscanf_s(inputFile, "%hhu", &c.numroom);
fwscanf_s(inputFile, L"%s", c.lastname, _countof(c.lastname));
fwrite(&c, sizeof(struct Computer), 1, outputFile);
}
_fcloseall();
return;
}
void find()
{
FILE *outputFile;
fopen_s(&outputFile, "output.dat", "rb+");
Computer c;
while (fread(&c, sizeof(struct Computer), 1, outputFile))
{
if (c.year == 1995 && wcscmp(L"IBM HC-486", c.mark) == 0)
{
wprintf_s(L"\nmark = %s year = %i month = %i day = %i numroom = %i lastname = %s",
c.mark, c.year, c.month, c.day, c.numroom, c.lastname);
_getch();
_fcloseall();
return;
}
}
_getch();
return;
}
int getdays(int year, int month)
{
int days = 0;
if (month == 4 || month == 6 || month == 9 || month == 11)
days = 30;
else if (month == 2)
{
bool leapyear = (year % 4 == 0 && year % 100 != 0) || (year % 400 == 0);
if (leapyear == 0)
days = 28;
else
days = 29;
}
else
days = 31;
return days;
}
void correction()
{
FILE* outputFile;
fopen_s(&outputFile, "output.dat", "rb+");
fseek(outputFile, 0, 0);
Computer c;
long item = 0;
while (fread(&c, sizeof(struct Computer), 1, outputFile))
{
while (c.month < 1 || c.month > 12)
{
wprintf_s(L"mark = %s year = %i month = %i day = %i numroom = %i lastname = %s",
c.mark, c.year, c.month, c.day, c.numroom, c.lastname);
wprintf_s(L"%s%i", L"Некорректный номер месяца \nПожалуйста введите другой номер месяца:", c.month);
scanf_s("%i", &c.month);
fseek(outputFile, item * sizeof(struct Computer), 0);
fwrite(&c, sizeof(struct Computer), 1, outputFile);
}
while (c.day < 1 || c.day > getdays(c.year, c.month))
{
wprintf_s(L"mark = %s year = %i month = %i day = %i numroom = %i lastname = %s",
c.mark, c.year, c.month, c.day, c.numroom, c.lastname);
wprintf_s(L"%s%i", L"Некорректный номер дня\nПожалуйста введите другой номер дня:", c.day);
scanf_s("%i", &c.day);
fseek(outputFile, item * sizeof(struct Computer), 0);
fwrite(&c, sizeof(struct Computer), 1, outputFile);
}
item += 1;
}
_getch();
_fcloseall();
return;
}
void print()
{
FILE* outputFile;
fopen_s(&outputFile, "output.dat", "rb+");
fseek(outputFile, 0, SEEK_SET);
Computer c;
while (fread(&c, sizeof(struct Computer), 1, outputFile))
{
wprintf_s(L"mark = %s year = %d month = %i day = %i numroom = %i lastname = %s",
c.mark, c.year, c.month, c.day, c.numroom, c.lastname);
}
_getch();
_fcloseall();
return;
}
Lab2.cpp
#include <windows.h>
#include "Lab.h"
int main()
{
SetConsoleCP(65001);
SetConsoleOutputCP(65001);
input();
print();
//find();
//correction();
return 0;
}

There are two main problems with that. The first one has already been pointed out by Johnny Mopp, in that your call to fgetws requires a minimum size of c.mark of 11 elements, so you are overflowing it.
And regarding why you read 0 as the year, it's due to this overflow and the fact that you are trying to manually add the NULL terminator to c.mark:
c.mark[wcslen(c.mark) - 1] = '\0';
As you are already overflowing c.mark, this happens to go right into c.year and sets it to 0 (try putting this line right after reading c.mark and you will see that you read the correct year).
In fact, this is not necessary because fgetws already includes the NULL terminator (your call will only read 10 characters and add as character 11 the '\0'.
Event then, take into account that your attempt to add the NULL terminator is bound to fail, because wcslen does not work unless there is already a NULL terminator, so you are trying to set a NULL terminator where there is already one. Besides, you are removing the last character in the string due to the -1.
Imagine that you have a string with only one character L"A". If you make that operation, wcslen will return 1 and if you substract 1, you are doing c.str[0] = L'\0', thus converting the string to L"". In this case, it would be better using sizeof instead of wcslen, because it would return 11 regardless of the content, and substracting 1 you would get c.str[10] = '\0' which is what you really want.
Nevertheless, as I said before, it's unnecessary because fgetws already takes care of the NULL terminator for you (take a look at the Remarks section of https://learn.microsoft.com/es-es/cpp/c-runtime-library/reference/fgets-fgetws?view=msvc-160).
UPDATE
Regarding the decission on when to end reading, I usually read until I run out of data, regardless of the file size. That would mean making the loop run forever with while (true), and checking the output of the fgetws and fscanf, as others have suggested. If you take a look at the documentation of fgetws (the link I wrote before) you can see in the Return value section that it returns a pointer to the buffer on success (this is not useful normally) but it returns NULL in case of an error or end-of-file. You can use this to break the loop if there is an error when you read mark by doing:
if (fgetws(c.mark, 11, inputFile) == NULL)
break;
Similarly, fscanf_s returns EOF in case of an error or end-of-file (https://learn.microsoft.com/es-es/cpp/c-runtime-library/reference/fscanf-s-fscanf-s-l-fwscanf-s-fwscanf-s-l?view=msvc-160), so you could possibly add that condition whenever you read a value using fscanf_s. For instance:
if (fscanf_s(inputFile, "%d", &c.year) == EOF)
break;
And so with the rest. Or you could go just with the condition in fgetws, but that could lead to corrupt records if you have incomplete lines (where the fgetws succeeds but one or more of the fscanf_s fails). In the end it all boils down to how much work you want to put and how resilient do you want your code to be against invalid inputs.

Related

How to allow my C++ code to update variables?

I'm new to coding and C++.
The code below is meant to monitor a magswitch and a status led on another controller. The code needs to run once the magswitch pin goes high (this works).
The additional code for pulseIn, is what I hope to use to monitor different flash rates of the led when I get the code working. For now I'm just looking for the state variable to update with the if and else if statements.
When I toggle the statusPin, the code picks up the changing state, but I cannot get it to update the "state" and "statuspinstate" variables.
The statuspinstate variable shows as 1, even though it is initialized as 0.
I inserted all the serial prints to try and see where things are going wrong.
This is the serial print when "statusPin" is LOW:
statuspinstate: 0
rate1: 2147483647
period: 0.00
rate2: 0
ontime: 0
offtime: 0
state: 0
statepinstatus: 1
This is the serial print when "statusPin" is HIGH
statuspinstate: 1
rate1: 2147483647
period: 0.00
rate2: 0
ontime: 0
offtime: 0
state: 0
statepinstatus: 1
Code:
const int statusPin = 19; //Reads status led
const int magSwitch = 22; //Magswitch to detect movement
int ontime,offtime,rate1,rate2;
float freq,period;
volatile unsigned int state =0;
volatile unsigned int statuspinstate = 0;
void setup()
{
pinMode(statusPin, INPUT); //input from controller
pinMode(magSwitch, INPUT);
Serial.begin(115200);
}
void loop()
{
while (digitalRead(magSwitch) == LOW) {
}
{
statuspinstate = digitalRead(statusPin);
ontime = pulseIn(statusPin,HIGH);
offtime = pulseIn(statusPin,LOW);
period = ontime+offtime;
rate1 = (ontime/period); //future use
rate2 = (offtime); //future use
Serial.println(String("statuspinstate ") + (digitalRead(statusPin))); //all serial print is debug info
Serial.println(String("rate1: ") + (rate1));
Serial.println(String("period: ") + (period));
Serial.println(String("rate2: ") + (rate2));
Serial.println(String("ontime: ") + (ontime));
Serial.println(String("offtime: ") + (offtime));
delay(500);
}
if ((ontime) != 0)
state = period;
else if (statuspinstate = 1)
state = 9999;
else if (statuspinstate = 0);
state = 0;
Serial.println(String("state: ") + (state));
Serial.println(String("statepinstatus: ") + (statuspinstate));
statuspinstate = 0; //return statuspinstate to zero
}
Look at your conditional, with proper indentation (do get a text editor that can indent your code for you):
if ((ontime) != 0)
state = period;
else if (statuspinstate = 1)
state = 9999;
else if (statuspinstate = 0);
state = 0;
We know that ontime is zero, so the second condition is tried next.
Now, statuspinstate = 1 is an assignment, not a comparison, and its value is "truth-y" so you take that branch.
Next, the stray semicolon in if (statuspinstate = 0); (which is also an assignment condition, but not evaluated) makes state = 0 unconditional.
So every time ontime is zero, you end up executing statuspinstate = 1 and state = 0.
What you probably want is
if (ontime != 0)
state = period;
else if (statuspinstate == 1)
state = 9999;
else if (statuspinstate == 0)
state = 0;

c++ copy array to array

I have taken code from here Webduino Network Setp
I added one more field.
struct config_t
{
....
...
.....
byte subnet[4];
byte dns_server[4];
unsigned int webserverPort;
char HostName[10]; // Added code Here..
} eeprom_config;
Snippet..
#define NAMELEN 5
#define VALUELEN 10
void setupNetHTML(WebServer &server, WebServer::ConnectionType type, char *url_tail, bool tail_complete)
{
URLPARAM_RESULT rc;
char name[NAMELEN];
char value[VALUELEN];
boolean params_present = false;
byte param_number = 0;
char buffer [13];
.....
.....
}
Added Lines to read date from web page and Wire to eeprom
Write to eeprom: ( Facing issue here, I need to copy value to eeprom_config.HostName[0] ... )
// read Host Name
if (param_number >= 25 && param_number <= 35) {
// eeprom_config.HostName[param_number - 25] = strtol(value, NULL, 10);
eeprom_config.HostName[param_number - 25] = value ; // Facing Issue here..
}
and...
for (int a = 0; a < 10; a++) {
server.printP(Form_input_text_start);
server.print(a + 25);
server.printP(Form_input_value);
server.print(eeprom_config.HostName[a]);
server.printP(Form_input_size1);
server.printP(Form_input_end);
}
Issue was resolved.
Thanks , got idea from this post.
invalid conversion from char' tochar*'
How ! changed
// read Host Name
if (param_number >= 25 && param_number <= 35) {
// eeprom_config.HostName[param_number - 25] = strtol(value, NULL, 10);
eeprom_config.HostName[param_number - 25] = value ; // Facing Issue here..
}
changed to
// read Host Name
if (param_number >= 25 && param_number <= 35) {
eeprom_config.HostName[param_number - 25] = value[0];
}

How to find out the next time when the clock will be adjusted for Daylight Saving?

I'm curious, if there's any way to find out the UTC date/time when the next Daylight Saving adjustment will take place?
Something akin to what Windows reports (see circled):
This information is provided in Windows by the EnumDynamicTimeZoneInformation function.
See http://msdn.microsoft.com/en-us/library/windows/desktop/hh706893%28v=vs.85%29.aspx
There is a database that has code and data: http://www.iana.org/time-zones
I don't think there's a specific API for this. I would just do a binary search, using localtime (and maybe time and mktime) from <ctime> (C++) or <time.h> (C).
A basic approach is to scan ahead three months at a time until the tm_isdst flag in the returned data structure is flipped. Then you can start binary searching between the last two two dates to figure out exactly when it flips.
See http://www.cplusplus.com/reference/ctime/tm/ for reference material.
I appreciate all your replies. And, yes, indeed I was asking about a WinAPI for Windows.
I did more research and came up with the following method that does what I wanted. It uses C++ and MFC's COleDateTime for easier date/time calculations. Other than that it's just C++ and WinAPIs. Please check if I understood the documentation for the DYNAMIC_TIME_ZONE_INFORMATION correctly. Here's the code:
int GetNextDaylightSavingAdjustmentTime(SYSTEMTIME* pOutDtNextDST_Local, int* pnOutAdjustmentMin)
{
//Get next time when DST adjustment will take place
//'pOutDtNextDST_Local' = if not NULL, receives the (local) time when next DST adjustment will take place
//'pnOutAdjustmentMin' = if not NULL, receives the amount of adjustment in minutes
//RETURN:
// = 1 if got the time, or
// = 0 if DST is not used
// = -1 if error (check GetLastError() for info)
int nOSError = NO_ERROR;
//Load API dynamically (in case of Windows XP)
BOOL (WINAPI *pfnGetDynamicTimeZoneInformation)(PDYNAMIC_TIME_ZONE_INFORMATION);
(FARPROC&)pfnGetDynamicTimeZoneInformation =
::GetProcAddress(::GetModuleHandle(L"Kernel32.dll"), "GetDynamicTimeZoneInformation");
DWORD tzID;
SYSTEMTIME StandardDate;
SYSTEMTIME DaylightDate;
int nBiasDaylight;
//Use newer API if possible
if(pfnGetDynamicTimeZoneInformation)
{
DYNAMIC_TIME_ZONE_INFORMATION dtzi = {0};
tzID = pfnGetDynamicTimeZoneInformation(&dtzi);
StandardDate = dtzi.StandardDate;
DaylightDate = dtzi.DaylightDate;
nBiasDaylight = dtzi.DaylightBias;
}
else
{
//Older API
TIME_ZONE_INFORMATION tzi = {0};
tzID = GetTimeZoneInformation(&tzi);
StandardDate = tzi.StandardDate;
DaylightDate = tzi.DaylightDate;
nBiasDaylight = tzi.DaylightBias;
}
int nRes = -1;
int nAdjMins = 0;
SYSTEMTIME stDstChange;
memset(&stDstChange, 0, sizeof(stDstChange));
SYSTEMTIME stDst;
if(tzID == TIME_ZONE_ID_STANDARD ||
tzID == TIME_ZONE_ID_DAYLIGHT)
{
stDst = tzID != TIME_ZONE_ID_DAYLIGHT ? DaylightDate : StandardDate;
if(stDst.wMonth >= 1 &&
stDst.wMonth <= 12 &&
stDst.wDay >= 1 &&
stDst.wDayOfWeek >= 0 &&
stDst.wDayOfWeek <= 6)
{
//Get adjustment bias
nAdjMins = tzID != TIME_ZONE_ID_DAYLIGHT ? -nBiasDaylight : nBiasDaylight;
if(stDst.wYear == 0)
{
//Relative date
SYSTEMTIME stLocal;
::GetLocalTime(&stLocal);
//Begin from the 1st day of the month &
//make sure that the date is in the future
COleDateTime dt;
for(int nYear = stLocal.wYear;; nYear++)
{
dt.SetDateTime(nYear, stDst.wMonth, 1, stDst.wHour, stDst.wMinute, stDst.wSecond);
if(dt > COleDateTime::GetCurrentTime())
break;
}
int nRequiredWeek = stDst.wDay >= 1 && stDst.wDay <= 5 ? stDst.wDay : 5;
for(int nCntDOW = 1;;)
{
//0=Sunday, 1=Monday; 2=Tuesday; 3=Wednesday; 4=Thursday; 5=Friday; 6=Saturday
int dow = dt.GetDayOfWeek() - 1;
ASSERT(dow >= 0 && dow <= 6);
if(dow == stDst.wDayOfWeek)
{
if(nCntDOW >= nRequiredWeek)
{
//Stop
break;
}
else
{
nCntDOW++;
}
}
//Go to next day
dt += COleDateTimeSpan(1, 0, 0, 0);
}
//Convert back to system time
if(dt.GetAsSystemTime(stDstChange))
{
//Success
nRes = 1;
}
else
{
//Failed
nOSError = ERROR_INVALID_FUNCTION;
ASSERT(NULL);
}
}
else
{
//Absolute date
stDstChange = stDst;
nRes = 1;
}
}
else
{
//Failed
nOSError = ERROR_INVALID_PARAMETER;
ASSERT(NULL);
}
}
else
{
//DST is not used
if(tzID == TIME_ZONE_ID_UNKNOWN)
{
nRes = 0;
}
else
{
//Error
nOSError = ERROR_INVALID_DATA;
ASSERT(NULL);
}
}
if(pOutDtNextDST_Local)
*pOutDtNextDST_Local = stDstChange;
if(pnOutAdjustmentMin)
*pnOutAdjustmentMin = nAdjMins;
::SetLastError(nOSError);
return nRes;
}
PS. And scratch my request for the UTC time. As I learned, it is easier to deal with local time in this situation.

How to avoid Switch Case & sscanf Function

I am working on C++. I am writing code for date format. Using with, we can get default date format from anyother date format. So I have found 240 date formats for this task. So M want to use switch case and sscanf function. Every case have sscanf function to separate day,month, year. So I need 240 cases and 240 sscanf function. Is there any method to avoid lot of swtich and sscanf? If you have any ideas, please let me know guys.
case 0:
sscanf(tsdate.c_str(),"%2d/%2d/%4d",&day,&month,&year);
break;
case 1:
sscanf(tsdate.c_str(),"%2d-%2d-%4d",&month,&day,&year);
break;
case 2:
sscanf(tsdate.c_str(),"%2d %2d %4d",&day,&month,&year);
break;
case 3:
sscanf(tsdate.c_str(),"%2d/%2d/%2d",&day,&month,&year);
coryear(year);
break;
case 4:
sscanf(tsdate.c_str(),"%2d/%2d/%2d",&year,&month,&day);
coryear(year);
break;
Like above, I want to put 240 cases and 240 sscanf. Please let me know how to avoid a lot of cases.
you can't avoid the switch cases but you can create multiple function to avoid sscanf:
void scanDayFirst(string format)
{
sscanf(tsdate.c_str(),format,&day,&month,&year);
break;
}
void scanMonthFirst(string format)
{
sscanf(tsdate.c_str(),format,&month,&day,&year);
break;
}
and so on.....
the result will be like this:
case 0:
scanDayFirst("%2d/%2d/%4d");
case 1:
scanDayFirst("%2d-%2d-%4d");
case 2:
scanDayFirst("%2d %2d %4d");
case 3:
scanDayFirst("%2d.%2d.%4d");
enum { ITEM_YEAR, ITEM_MONTH, ITEM_DAY, NUM_ITEMS };
struct date_format { char const *fmt; int items[NUM_ITEMS]; };
struct date_format const formats[] =
{ { "%2d/%2d/%4d", { ITEM_DAY, ITEM_MONTH, ITEM_YEAR } }
, { "%2d-%2d-%4d", { ITEM_MONTH, ITEM_DAY, ITEM_YEAR } }
/* etc. */
};
int parts[NUM_ITEMS]; /* Instead of year,month,day */
sscanf(tsdate.c_str(), formats[x].fmt,
&parts[formats[x].items[0]],
&parts[formats[x].items[1]],
&parts[formats[x].items[2]]);
You can extend this to have ITEM_NONE if you want to skip an item, or add extra items, and so on.
NB. If this is C++ then consider using stream input instead of sscanf.
Instead of enumerating all cases consider instead using a custom language for the format specification:
Date x = parseDate(user_input, "dd-mm-yyyy");
it will make the function shorter, easier to document and easier to use also improving the readability of the code that uses it. The idea is using codes like
yyyy ............. 4-digits year
yy ............... 2-digits year with automatic century computation
mm ............... 2-digits month
m ................ 1 or 2 digits month
dd ............... 2-digits day
d ................ 1 or 2 digits day
anything else .... mandatory character
A simple implementation could be
Date parseDate(const std::string& input, const std::string& format) {
const char *src = input.c_str();
const char *fmt = format.c_str();
int year=-1, month=-1, day=-1;
while (*fmt) {
if (!*src) throw invalid_date(input, format);
if (strncmp(fmt, "yyyy", 4) == 0) {
fmt += 4;
year = getInt(src, 4);
} else if (strncmp(fmt, "yy", 2) == 0) {
fmt += 2;
year = guess_century(getInt(src, 2));
} else if (strncmp(fmt, "mm", 2) == 0) {
fmt += 2;
month = getInt(src, 2);
} else if (fmt[0] == 'm') {
fmt += 1;
month = getInt(src, -1);
} else if (strncmp(fmt, "dd", 2) == 0) {
fmt += 2;
day = getInt(src, 2);
} else if (fmt[0] == 'd') {
fmt += 1;
day = getInt(src, -1);
} else {
if (src[0] != fmt[0]) throw invalid_date(input, format);
src++; fmt++;
}
}
if (*src || year == -1 || month == -1 || day == -1)
throw invalid_date(input, format);
return Date(year, month, day);
}
NOTE: untested

playing created Audio-Data has noise and periodical clicking in sound

I write an application, which plays a sound getting from Hardware (like a ring buffer filled with a sinus wave with certain frequency). Everything works fine, and I can playback the created sound correctly except a periodical clicking (maybe at the end of buffer?) and noise.
I initialize and run the Buffer:
void Audiooutput::InitializeAudioParameters()
{
Audio_DataWritten = 0;
Audio_fragments = 4;
Audio_channels = 2;
Audio_BufferSize = 256;
Audio_Samplerate = 8000;
Audio_ResamplingFactor = 1;
Audio_Framesize = 2;
// (SND_PCM_FORMAT_S16_LE / 8);
Audio_frames = Audio_BufferSize / Audio_Framesize * Audio_fragments;
snd_pcm_uframes_t size;
err = snd_pcm_hw_params_any(pcmPlaybackHandle, hw_params);
err = snd_pcm_hw_params_set_rate_resample(pcmPlaybackHandle, hw_params, 1);
// qDebug()<<a1.sprintf(" % d \t snd_pcm_hw_params_set_rate: %s",Audio_Samplerate,snd_strerror(err));
err =
snd_pcm_hw_params_set_format(pcmPlaybackHandle, hw_params,
SND_PCM_FORMAT_S16_LE);
err =
snd_pcm_hw_params_set_channels(pcmPlaybackHandle, hw_params,
Audio_channels);
err = snd_pcm_hw_params_set_rate_near(pcmPlaybackHandle, hw_params, &Audio_Samplerate, 0);
// qDebug()<<a1.sprintf(" % d \t snd_pcm_hw_params_set_rate: %s",Audio_Samplerate,snd_strerror(err));
if ((err =
snd_pcm_hw_params_set_periods_near(pcmPlaybackHandle, hw_params,
&Audio_fragments, 0)) < 0) {
qDebug() << a1.sprintf("Error setting # fragments to %d: %s\n",
Audio_fragments, snd_strerror(err));
} else
qDebug() << a1.sprintf("setting # fragments to %d: %s\n",
Audio_fragments, snd_strerror(err));
err = snd_pcm_hw_params_get_buffer_size(hw_params, &size);
if ((err =
snd_pcm_hw_params_set_buffer_size_near(pcmPlaybackHandle,
hw_params,
&Audio_frames)) < 0) {
qDebug() << a1.
sprintf("Error setting buffer_size %d frames: %s",
Audio_frames, snd_strerror(err));
} else
qDebug() << a1.sprintf("setting Buffersize to %d --> %d: %s\n",
Audio_BufferSize, Audio_frames,
snd_strerror(err));
Audio_BufferSize = Audio_frames;
if ((err = snd_pcm_hw_params(pcmPlaybackHandle, hw_params)) < 0) {
qDebug() << a1.sprintf("Error setting HW params: %s",
snd_strerror(err));
}
Q_ASSERT(err >= 0);
}
void Audiooutput::ProduceAudioOutput(int n, int mmodes, int totalMModeGates,
short *sinusValue, short *cosinusValue)
{
for (int audioSample = 0; audioSample < n;
audioSample += Audio_ResamplingFactor) {
currentposition =
(int)(m_Audio.generalPos % (Audio_BufferSize / 2));
if (currentposition == 0) {
QueueAudioBuffer();
m_Audio.currentPos = 0;
}
m_Audio.generalPos++;
AudioData[currentposition * 2] =
(short)(sinusValue[audioSample]);
AudioData[currentposition * 2 + 1] =
(short)(cosinusValue[audioSample]);
}
}
void Audiooutput::QueueAudioBuffer()
{
snd_pcm_prepare(pcmPlaybackHandle);
Audio_DataWritten +=
snd_pcm_writei(pcmPlaybackHandle, AudioData, Audio_BufferSize);
}
Changing the audiobuffer size or fragments changes also the clicking period.
Can anyone help me with this issue ?
I checked also the first and Last Values. Thy are always difference.
OS: Ubuntu 11
more detail.
the count of received data is dynamically, and changes depend of different parameters. But I play always a certain part e.g. 128 values or 256 or 512....
// I get the Audiodata from a hardware (in a Timerloop)
audiobuffersize = 256;
short *AudioData = new short[256];
int generalAudioSample = 0;
void CollectDataFromHw()
{
...
int n = 0;
n = GetData(buf1,buf2);//buf1 = new short[MAX_SHRT]
if(n > 0)
FillAudioBuffer(n,buf1,buf2)
...
}
-------------------------------------------
void FillAudioBuffer(int n, short*buf1, short*buf2)
{
for(int audioSample = 0;audioSample < n; audioSample++){
iCurrentAudioSample = (int)(generalAudioSample % (audiobuffersize/2));
if(iCurrentAudioSample == 0) {
snd_pcm_writei(pcmPlaybackHandle,AudioData,audiobuffersize );
memset(AudioData,0x00,audiobuffersize*sizeof(short));
}
generalAudioSample++;
AudioData[iCurrentAudioSample * 2] = (short)(buf1[audioSample];
AudioData[iCurrentAudioSample * 2 +1] = (short)(buf2[audioSample];
}
}
I changed the audiobuffersize also. If I set it to a bigger size, I have some Echo additional to clicks.
any Idea ?
//-----------------------
the Problem is
snd_pcm_prepare(pcmPlaybackHandle);
every call of this function produce a click in sound !
Can't test the source code, but I think that the high-frequency clicks you hear are discontinuities in the sound wave. You have to assure that looping period (or, buffer size) is multiple of wave period.
Check if first and last value of buffer are almost the same (+/- 1, for example). Their distance determines the amplitude of the unwanted click.
solved
buffer has been played several times before it was filled with the data.
stupid error in the code.missing a parantez --> audio_buffersize/2 <--
and therefore the result was very often if(iCurrentAudioSample == 0) true !!!!!
iCurrentAudioSample = (int)(generalAudioSample % (audio_buffersize/2));
if(iCurrentAudioSample == 0)
{
writetoaudioStream(audiobuffer);
}