Ogg to Riff/Wave encoding with acm - c++

My task is to record wave file, convert it to ogg and pack it to the riff container. First two parts were done, but I have problems with the third part. I've found a source code which can solve my problem, but it doesn't work correctly.
#include <windows.h>
#include <windowsx.h>
#include <mmsystem.h>
#include <memory.h>
#include <stdlib.h>
#include <mmreg.h>
#include <msacm.h>
#include <assert.h>
#include <math.h>
#include <time.h>
#include <sys/types.h>
#include <sys/stat.h>
#define INPUT "record.wav"
#define OUTPUT "output_ogg.wav"
/* The following taken from the vorbis.acm sources */
/* Defines modes for encoding. Set this in 'fmt ' */
#define WAVE_FORMAT_VORBIS1 ((WORD)'O'+((WORD)'g'<<8)) // 0x674f("Og") ... Original stream compatible
#define WAVE_FORMAT_VORBIS2 ((WORD)'P'+((WORD)'g'<<8)) // 0x6750("Pg") ... Have independent header
#define WAVE_FORMAT_VORBIS3 ((WORD)'Q'+((WORD)'g'<<8)) // 0x6751("Qg") ... Have no codebook header
#define WAVE_FORMAT_VORBIS1P ((WORD)'o'+((WORD)'g'<<8)) // 0x676f("og") ... Original stream compatible
#define WAVE_FORMAT_VORBIS2P ((WORD)'p'+((WORD)'g'<<8)) // 0x6770("pg") ... Have independent header
#define WAVE_FORMAT_VORBIS3P ((WORD)'q'+((WORD)'g'<<8)) // 0x6771("qg") ... Have no codebook header
/* The 'fact' chunk required for compressed WAV files */
struct FACT {
unsigned long dwID;
unsigned long dwSize;
unsigned long dwSamples;
};
int main()
{
/* Open source file */
HMMIO hSrcWaveFile=mmioOpen(INPUT,NULL,MMIO_READ);
assert(hSrcWaveFile);
MMCKINFO SrcWaveFile;
mmioDescend(hSrcWaveFile,&SrcWaveFile,NULL,0);
assert(SrcWaveFile.ckid==mmioStringToFOURCC("RIFF",MMIO_TOUPPER));
assert(SrcWaveFile.fccType==mmioStringToFOURCC("WAVE",MMIO_TOUPPER));
MMCKINFO SrcWaveFmt;
/* Go to RIFF-WAVE*/
mmioDescend(hSrcWaveFile,&SrcWaveFmt,&SrcWaveFile,0);
assert(SrcWaveFmt.ckid==mmioStringToFOURCC("fmt ",0));
int SrcHeaderSize=SrcWaveFmt.cksize;
if(SrcHeaderSize<sizeof(WAVEFORMATEX))
SrcHeaderSize=sizeof(WAVEFORMATEX);
WAVEFORMATEX *SrcHeader=(WAVEFORMATEX *)new char[SrcHeaderSize];
ZeroMemory(SrcHeader,SrcHeaderSize);
/* Read fmt */
mmioRead(hSrcWaveFile,(char*)SrcHeader,SrcWaveFmt.cksize);
/* Leave the chunk */
mmioAscend(hSrcWaveFile,&SrcWaveFmt,0);
MMCKINFO SrcWaveData;
while(1){
MMRESULT Result=mmioDescend(hSrcWaveFile,&SrcWaveData,&SrcWaveFile,0);
assert(Result==0);
if(SrcWaveData.ckid==mmioStringToFOURCC("data",0))
break;
Result=mmioAscend(hSrcWaveFile,&SrcWaveData, 0);
assert(Result==0);
}
/* Destination header */
WAVEFORMATEX *DstHeader=(WAVEFORMATEX *)malloc(1024);
ZeroMemory(DstHeader,1024);
printf ("Going ACM!\n");
/* Suggest a format for us */
/* Try to coose the nmber 3 mode (whatever that is) */
DstHeader->wFormatTag = WAVE_FORMAT_VORBIS3;
DstHeader->nChannels = 2;
DstHeader->wBitsPerSample = 16;
DstHeader->nSamplesPerSec = 44100;
printf ("->acmFormatSuggest()\n");
if (acmFormatSuggest(NULL,SrcHeader,DstHeader,1024,ACM_FORMATSUGGESTF_WFORMATTAG))
printf ("ERROR: acmFormatSuggest()\n");
/* We shoudl have the DstHeader filled with data byt the ACM now */
/* Open destination */
HMMIO hDstWaveFile;
/* open the destination file */
hDstWaveFile=mmioOpen(OUTPUT,NULL,MMIO_CREATE|MMIO_WRITE);
assert(hDstWaveFile);
printf ("->mmioOpen() output.wav\n");
/* Create chunks */
MMCKINFO DstWaveFile;
DstWaveFile.fccType=mmioStringToFOURCC("WAVE",MMIO_TOUPPER);
mmioCreateChunk(hDstWaveFile,&DstWaveFile,MMIO_CREATERIFF);
printf ("->mmioCreateChunk() WAVE\n");
/* Create format chunk */
MMCKINFO DstWaveFmt;
DstWaveFmt.ckid=mmioStringToFOURCC("fmt ",0);
/* Create chunk write data and Ascend out of it */
mmioCreateChunk(hDstWaveFile,&DstWaveFmt,0);
printf ("->mmioCreateChunk() fmt\n");
mmioWrite(hDstWaveFile,(char*)DstHeader,sizeof(WAVEFORMATEX)+DstHeader->cbSize);
printf ("->mmioWrite() fmt header\n");
mmioAscend(hDstWaveFile,&DstWaveFmt,0);
printf ("->mmioAscend()\n");
/* fact chunk */
/* this is only my idea of what it should look like */
/* i found that some WAV files had more data than i write */
/* but that seems enough for most of apps i tested */
FACT DstFactChunk;
MMCKINFO FactChunk;
DstFactChunk.dwID = mmioStringToFOURCC ("fact", 0);
DstFactChunk.dwSamples = SrcWaveData.cksize / 4;
DstFactChunk.dwSize = sizeof (DstFactChunk) - sizeof (DstFactChunk.dwID) - sizeof (DstFactChunk.dwSize);
FactChunk.ckid = mmioStringToFOURCC ("fact", 0);
FactChunk.cksize = DstFactChunk.dwSize;
/* Calculate the time */
float TIME;
if (SrcHeader->nSamplesPerSec == 44100)
TIME = DstFactChunk.dwSamples / 44100.f;
mmioWrite (hDstWaveFile, (char *)&DstFactChunk, sizeof (DstFactChunk));
/* This ascend produced an error when i added this whole code */
/* to my Dialog based MFC full feature super duper app */
/* Don't know why really but i think that Write already moves the pointer */
/* past the chun sok this is unnecessery */
/* mmioAscend (hDstWaveFile, &FactChunk, 0); */
/* Create Data chunk */
MMCKINFO DstWaveData;
DstWaveData.ckid=mmioStringToFOURCC("data",0);
mmioCreateChunk(hDstWaveFile,&DstWaveData,0);
mmioAscend (hDstWaveFile, &DstWaveData, 0);
printf ("->mmioCreateChunk() data\n");
/* Print the data we have gathered so far */
printf ("------------Source-----------\n");
printf ("Format: \t\t%X\n", SrcHeader->wFormatTag);
printf ("Channels: \t\t%d\n", SrcHeader->nChannels);
printf ("Samples/Sec: \t\t%d\n", SrcHeader->nSamplesPerSec);
printf ("AverageBytes/Sec: \t%d\n", SrcHeader->nAvgBytesPerSec);
printf ("Bits/Sample: \t\t%d\n", SrcHeader->wBitsPerSample);
printf ("BlockAlign: \t\t%d\n", SrcHeader->nBlockAlign);
printf ("DataSize: \t\t%d\n", SrcWaveData.cksize);
printf ("Time: \t\t\t%.3f\n", TIME);
printf ("Samples: \t\t%d\n", DstFactChunk.dwSamples);
printf ("Extra: \t\t\t%d\n", SrcHeader->cbSize);
printf ("------------------------------\n");
printf ("\n------------Destination------\n");
printf ("Format: \t\t%X\n", DstHeader->wFormatTag);
printf ("Channels: \t\t%d\n", DstHeader->nChannels);
printf ("Samples/Sec: \t\t%d\n", DstHeader->nSamplesPerSec);
printf ("AverageBytes/Sec: \t%d\n", DstHeader->nAvgBytesPerSec);
printf ("Bits/Sample: \t\t%d\n", DstHeader->wBitsPerSample);
printf ("BlockAlign: \t\t%d\n", DstHeader->nBlockAlign);
printf ("Extra: \t\t\t%d\n", DstHeader->cbSize);
printf ("------------------------------\n");
DWORD maxFormatSize = 0;
MMRESULT ACMres;
/* Get the max possbile size from the system this really no necessery */
/* but i was experimenting a bit and so I left it here */
ACMres = acmMetrics( NULL, ACM_METRIC_MAX_SIZE_FORMAT, &maxFormatSize );
if (ACMres != MMSYSERR_NOERROR){
printf ("ERROR: acmMetrics()\n");
}
/* Open ACM stream */
HACMSTREAM acm = NULL;
MMRESULT Result=acmStreamOpen(&acm,NULL,SrcHeader,DstHeader,NULL,0,0,0);
printf ("->acmStreamOpen()\n");
if (Result != MMSYSERR_NOERROR){
printf ("ERROR: acmStreamOpen()\n");
exit (-1);
}
/* This is where the problem's begin, first the buffers */
/* Size of the dest/src is based on the size of src/dest */
DWORD DefaultWriteSize;
DWORD DefaultReadSize = SrcHeader->nBlockAlign * 1024;
/* If we know the dest */
/* Result=acmStreamSize(acm, DefaultWriteSize, &DefaultReadSize, ACM_STREAMSIZEF_DESTINATION); */
printf ("->acmStreamSize()\n");
/* If we know the source, well stay with the source PCM is less problematic */
Result = acmStreamSize (acm, DefaultReadSize, &DefaultWriteSize, ACM_STREAMSIZEF_SOURCE);
printf ("->acmStreamSize() gave us buffer size [%d]\n", DefaultWriteSize);
if (Result != MMSYSERR_NOERROR){
printf ("ERROR: acmStreamSize()\n");
exit (-1);
}
/* Allocate memory */
ACMSTREAMHEADER stream;
ZeroMemory(&stream,sizeof(stream));
stream.cbStruct=sizeof(stream);
stream.pbSrc=(BYTE*)GlobalAlloc(GMEM_FIXED,DefaultReadSize);
stream.cbSrcLength=DefaultReadSize;
stream.pbDst=(BYTE*)GlobalAlloc(GMEM_FIXED,DefaultWriteSize);
stream.cbDstLength=DefaultWriteSize;
/* Prepare header */
printf ("->acmStreamPrepareHeader()\n");
Result=acmStreamPrepareHeader(acm, &stream,0);
if (Result != MMSYSERR_NOERROR){
printf ("ERROR: acmStreamPrepareHeader()\n");
exit (-1);
}
/* The main encoding loop */
/* I'm pretty sure that before the actual reading of samples from the source */
/* I should feed the ACM some junk so that it would write the necessery headers */
/* that Ogg Vorbis requires */
/* but i dont know how much of that 'junk' i would have to write there */
/* i don't know if it can be junk */
/* well i'm pretty clueless here */
for(int RemainSize=SrcWaveData.cksize;RemainSize>0;){
// ????
int ReadSize=DefaultReadSize;
if(ReadSize>RemainSize)
ReadSize=RemainSize;
RemainSize-=ReadSize;
ReadSize=mmioRead(hSrcWaveFile,(char*)stream.pbSrc,ReadSize);
if (ReadSize == -1){
printf ("Can't read\n");
break;
}
stream.cbSrcLength=ReadSize;
/* Convert */
Result=acmStreamConvert(acm,&stream,0);
if (Result)
printf ("ERROR: acmStreamConvert()\n");
int WriteSize=stream.cbDstLengthUsed;
/* Wrtie data */
Result=mmioWrite(hDstWaveFile,(char*)stream.pbDst,WriteSize);
if (Result == -1){
printf ("Can't Write");
break;
}
/* Uncomment this if you want to see the buffer sizes */
/* printf ("READ[%d] :: WRITE[%d]\n", stream.cbSrcLengthUsed, stream.cbDstLengthUsed); */
}
/* Cleaup on Isle 5 !!! */
GlobalFree(stream.pbSrc);
GlobalFree(stream.pbDst);
acmStreamUnprepareHeader(acm,&stream,0);
acmStreamClose(acm,0);
mmioAscend(hSrcWaveFile,&SrcWaveData,0);
mmioAscend(hSrcWaveFile,&SrcWaveFile,0);
mmioAscend(hDstWaveFile,&DstWaveData,0);
mmioAscend(hDstWaveFile,&DstWaveFile,0);
free(DstHeader);
mmioClose(hSrcWaveFile,0);
mmioClose(hDstWaveFile,0);
delete[] SrcHeader;
return 0;
}
When I'm trying to execute this program, it shows me that acmFormatSuggest() and acmStreamOpen() failes. Please, help me finding the error.

acmFormatSuggest (by the way, what is the error code?) would possibly succeed if there is an ACM audio codec installed, which supports this format. There is no one available by default, do you actually have one installed?

Related

Opus audio, opus_decode() always fills output buffer with zeros

I slightly modified the opus provide sample file "trivial_example.c"
I modified it so instead of loading a pcm file from disk, I just create some noise using random numbers. Maybe that is the problem, but I dont see how.
I am using Visual Studio 2019. Windows SDK 10. Windows7 x64.
none of the opus functions return an error.
opus_encode() seems to work. It fills cbits, as expected.
But opus_decode() only fills the output buffer with zeros.
This is opus provided sample code, but it doesnt work. Is there some computer setup I needed to do before using opus.
Ive been trying to get opus to work for days. Please help. Thank you.
#define FRAME_SIZE 960
#define SAMPLE_RATE 48000
#define CHANNELS 2
#define APPLICATION OPUS_APPLICATION_AUDIO
#define BITRATE 64000
#define MAX_FRAME_SIZE 6*960
#define MAX_PACKET_SIZE (3*1276)
int main(int argc, char **argv)
{
char *inFile;
FILE *fin;
char *outFile;
FILE *fout;
opus_int16 in[FRAME_SIZE*CHANNELS];
opus_int16 out[MAX_FRAME_SIZE*CHANNELS];
unsigned char cbits[MAX_PACKET_SIZE];
int nbBytes;
/*Holds the state of the encoder and decoder */
OpusEncoder *encoder;
OpusDecoder *decoder;
int err;
/*Create a new encoder state */
encoder = opus_encoder_create(SAMPLE_RATE, CHANNELS, APPLICATION, &err);
if (err<0)
{
fprintf(stderr, "failed to create an encoder: %s\n", opus_strerror(err));
return EXIT_FAILURE;
}
/* Set the desired bit-rate. You can also set other parameters if needed.
The Opus library is designed to have good defaults, so only set
parameters you know you need. Doing otherwise is likely to result
in worse quality, but better. */
err = opus_encoder_ctl(encoder, OPUS_SET_BITRATE(BITRATE));
if (err<0)
{
fprintf(stderr, "failed to set bitrate: %s\n", opus_strerror(err));
return EXIT_FAILURE;
}
/* Create a new decoder state. */
decoder = opus_decoder_create(SAMPLE_RATE, CHANNELS, &err);
if (err<0)
{
fprintf(stderr, "failed to create decoder: %s\n", opus_strerror(err));
return EXIT_FAILURE;
}
////////////////////////////////////////////////////////////////////// create audio noise
#define RandZeroToOne ((float)rand() / RAND_MAX)
#define RandNegOneToOne (((float)rand() / RAND_MAX)*2.0-1.0)
opus_int16* pcmdata = (opus_int16*)calloc(65536, sizeof(opus_int16));
opus_int16* pDstData = (opus_int16*)calloc(65536, sizeof(opus_int16));
for(short i=0;i<6553;i++)
{
pcmdata[i] = (opus_int16)(RandZeroToOne*32767.0);
if((i&0x1)==0)
pcmdata[i] = -pcmdata[i];
int T=0;
}
//////////////////////////////////////////////////////////////////////
//while (1)
{
int i;
int frame_size;
/* Convert from little-endian ordering. */
for (i=0;i<CHANNELS*FRAME_SIZE;i++)
in[i]=pcmdata[2*i+1]<<8|pcmdata[2*i];
/* Encode the frame. */
nbBytes = opus_encode(encoder, in, FRAME_SIZE, cbits, MAX_PACKET_SIZE);;//<---------------
if (nbBytes<0)
{
fprintf(stderr, "encode failed: %s\n", opus_strerror(nbBytes));
return EXIT_FAILURE;
}
/* Decode the data. In this example, frame_size will be constant because
the encoder is using a constant frame size. However, that may not
be the case for all encoders, so the decoder must always check
the frame size returned. */
opus_decoder_ctl(decoder, OPUS_RESET_STATE);
frame_size = opus_decode(decoder, cbits, nbBytes, out, MAX_FRAME_SIZE, 0);//<---------------
if (frame_size<0)
{
fprintf(stderr, "decoder failed: %s\n", opus_strerror(frame_size));
return EXIT_FAILURE;
}
/* Convert to little-endian ordering. */
for(i=0;i<CHANNELS*frame_size;i++)
{
pcmdata[2*i]=out[i]&0xFF;
pcmdata[2*i+1]=(out[i]>>8)&0xFF;
}
}
opus_encoder_destroy(encoder);
opus_decoder_destroy(decoder);
return EXIT_SUCCESS;
}

Declaring an object of a Windows API structure (DCB) - error C4430: missing type specifier - int assumed

I'm trying to create a C++ program to communicate with a serial port device using Windows API in Visual Studio Community 2017 on Windows 7.
Trying to compile this bit of code:
#include <iostream>
#include <Windows.h>
#include "stdafx.h"
#pragma hdrstop
using namespace std;
DCB dcb;
int main()
{
return 0;
}
I get these errors pointing to DCB dcb;:
error C4430: missing type specifier - int assumed. Note: C++ does not support default-int
error C2146: syntax error: missing ';' before identifier 'dcb'
The DCB structure is defined in Winbase.h like this:
typedef struct _DCB {
DWORD DCBlength; /* sizeof(DCB) */
DWORD BaudRate; /* Baudrate at which running */
DWORD fBinary: 1; /* Binary Mode (skip EOF check) */
DWORD fParity: 1; /* Enable parity checking */
DWORD fOutxCtsFlow:1; /* CTS handshaking on output */
DWORD fOutxDsrFlow:1; /* DSR handshaking on output */
DWORD fDtrControl:2; /* DTR Flow control */
DWORD fDsrSensitivity:1; /* DSR Sensitivity */
DWORD fTXContinueOnXoff: 1; /* Continue TX when Xoff sent */
DWORD fOutX: 1; /* Enable output X-ON/X-OFF */
DWORD fInX: 1; /* Enable input X-ON/X-OFF */
DWORD fErrorChar: 1; /* Enable Err Replacement */
DWORD fNull: 1; /* Enable Null stripping */
DWORD fRtsControl:2; /* Rts Flow control */
DWORD fAbortOnError:1; /* Abort all reads and writes on Error */
DWORD fDummy2:17; /* Reserved */
WORD wReserved; /* Not currently used */
WORD XonLim; /* Transmit X-ON threshold */
WORD XoffLim; /* Transmit X-OFF threshold */
BYTE ByteSize; /* Number of bits/byte, 4-8 */
BYTE Parity; /* 0-4=None,Odd,Even,Mark,Space */
BYTE StopBits; /* 0,1,2 = 1, 1.5, 2 */
char XonChar; /* Tx and Rx X-ON character */
char XoffChar; /* Tx and Rx X-OFF character */
char ErrorChar; /* Error replacement char */
char EofChar; /* End of Input character */
char EvtChar; /* Received Event character */
WORD wReserved1; /* Fill for now. */
} DCB, *LPDCB;`
When you are using precompiled headers, anything above the line
#include "stdafx.h"
(or whatever the name of the header designated for precompilation)
gets ignored.
Try rearranging your includes to put that one first.
More explanation on MSDN, particularly important is this:
The compiler treats all code occurring before the .h file as precompiled. It skips to just beyond the #include directive associated with the .h file, uses the code contained in the .pch file, and then compiles all code after filename.

Application of socket() from sys/socket.h

I'm writing a program in C++ to establish communication with a DLP Lightcrafter (Texas Instruments) without the provided GUI, and I've used these instructions to establish the connection:
#include <stdlib.h>
#include <string.h>
#include <iostream> /* cout */
#include <sys/types.h>
#include <netinet/in.h>
#include <sys/socket.h> /* socket struct */
#include <arpa/inet.h> /* ip, etc */
#include <unistd.h> /* read() write() for socket */
#include <cstdint>
#include "PKT.h" /* calcChecksum() */
using namespace std;
/* Packet format
* ------------------------------------------------------------------------------------
* | HEADER | DATA | CHECKSUM |
* ------------------------------------------------------------------------------------
* | Byte 0 | Byte 1 | Byte 2 | Byte 3 | Byte 4 | Byte 5 | Byte 6...Byte N | Byte N+1 |
* ------------------------------------------------------------------------------------
* |Pkt type| CMD 1 | CMD 2 | Flags | Payload length | Data payload | Checksum |
* ------------------------------------------------------------------------------------ */
int main ()
{
enum Type{BUSY, ERROR, WRITE, WRITE_RESP, READ, READ_RESP};
enum Flag{SINGLE, FIRST, MID, LAST};
enum CurDispMode{STATIC,INTERNAL_PAT,HDMI,RESERVED,PATTERN_SEQ};
enum CurTestPat{CHECKERBOARD_14X8,SOLID_BLACK,SOLID_WHITE,SOLID_GREEN,SOLID_BLUE,SOLID_RED,VERT_LINES_1W7B,HORIZ_LINES_1W7B,VERT_LINES_1W1B,HORIZ_LINES_1W1B,DIAG_LINES,VERT_GRAY_RAMPS,HORIZ_GRAY_RAMPS,CHECKERBOARD_4X4};
enum PKT_Size{HEADER=6, MAX=0xFFFF, CHECK=1};
char ip[] = "192.168.1.100";
int *pkt=new int [HEADER+MAX+CHECK];
unsigned int data_length, pkt_length;
unsigned int cmd_CurDispMode=0x0101;
unsigned int cmd_CurTestPat=0x0103;
/* Socket Structure */
struct sockaddr_in sa;
sa.sin_family=AF_INET;
sa.sin_addr.s_addr=inet_addr(ip);
sa.sin_port = htons(0x5555);
int s = socket(AF_INET,SOCK_STREAM,0);
/* Attempt to Establish Connection */
if (connect(s,(sockaddr*) &sa,sizeof(sa))!=-1){
cout<<"Connected."<<endl;
cout<<" "<<endl;
usleep(1000000);
/* #################################### */
/* Request to Display SOLID BLUE SCREEN */
/* #################################### */
data_length=1;
if(data_length>MAX)
return -1;
/* First instruction - set test pattern mode */
pkt[0]=WRITE;
pkt[1]=(cmd_CurDispMode >> 8) & 0xFF;
pkt[2]=(cmd_CurDispMode) & 0xFF;
pkt[3]=SINGLE;
pkt[4]=data_length & 0xFF;
pkt[5]=(data_length >> 8) & 0xFF;
pkt[6]=INTERNAL_PAT;
pkt[HEADER+data_length]=calcChecksum(HEADER+data_length, pkt);
pkt_length=HEADER+data_length+CHECK;
if(send(s,(const void *)pkt,(size_t) pkt_length,0) != pkt_length){
cout<<"PKT writing failed."<<endl;
return -1;}
cout<<pkt[0]<<" "<<pkt[1]<<" "<<pkt[2]<<" "<<pkt[3]<<" "<<pkt[4]<<" "<<pkt[5]<<" "<<pkt[6]<<" "<<pkt[7]<<endl;
/* Retrieves answer from DLP */
if(recv(s,(void *)pkt,(size_t)HEADER,0) != HEADER){
cout<<"CMD reading failed."<<endl;
return -1;}
/* New Data Length */
data_length = pkt[4] | pkt[5] << 8;
/* Retrieves Data & CHECKSUM */
if(recv(s,(void *)(pkt+HEADER),(size_t)(data_length+1),0) != data_length+1){
cout<<"Payload reading failed."<<endl;
return -1;}
cout<<pkt[0]<<" "<<pkt[1]<<" "<<pkt[2]<<" "<<pkt[3]<<" "<<pkt[4]<<" "<<pkt[5]<<" "<<pkt[6]<<" "<<pkt[7]<<endl;
/* CHECKSUM */
if(pkt[data_length+HEADER] != calcChecksum(data_length+HEADER,pkt)){
cout<<"Checksum Error"<<endl;
return -1;}
data_length=1;
/* Second instruction - display pattern 0x05 */
pkt[0]=WRITE;
pkt[1]=(cmd_CurTestPat >> 8) & 0xFF;
pkt[2]=(cmd_CurTestPat) & 0xFF;
pkt[3]=SINGLE;
pkt[4]=data_length & 0xFF;
pkt[5]=(data_length >> 8) & 0xFF;
pkt[6]=SOLID_BLUE;
pkt[HEADER+data_length]=calcChecksum(HEADER+data_length, pkt);
if(send(s,(const void *)pkt,(size_t)pkt_length,0) != pkt_length){
cout<<"PKT writing failed."<<endl;
return -1;}
/* Retrieves answer from DLP */
if(recv(s,(void *)pkt,(size_t)HEADER,0) != HEADER){
cout<<"CMD reading failed."<<endl;
return -1;}
/* New Data Length */
data_length = pkt[4] | pkt[5] << 8;
/* Retrieves Data */
if(recv(s,(void *)(pkt+HEADER),(size_t)(data_length+1),0) != data_length+1){
cout<<"Payload reading failed."<<endl;
return -1;}
cout<<pkt[HEADER]<<" "<<pkt[HEADER+1]<<endl;
/* CHECKSUM */
if(pkt[data_length+HEADER] != calcChecksum(data_length+HEADER,pkt)){
cout<<"Checksum Error"<<endl;
return -1;}
if(pkt[0] != WRITE_RESP){
cout<<"CMD Failed."<<endl;
return -1;}
if(pkt[3]==LAST)
cout<<"CMD Success."<<endl;
/* ############## */
/* End of Request */
/* ############## */
usleep(9000000);
if(!close(s))
cout<<"Disconnected."<<endl;
}
else
cout<<"Connection failed."<<endl;
delete [] pkt;
return 0;
}
When I try to connect to the board it's successful however when I send it commands I only get an error returned. I can't find mistakes in the way I'm sending the commands nor in the commands themselves, and since I'm don't really understand the way the socket works I thought maybe that's the issue...any thoughts?
Thanks
Edit:
I have edited the code to include an example of a set of instructions.
To communicate with the DLP vectors with 8bit components are sent.
First position defines what type of packet it is;
Second and third position are the MSB and LSB of the command to be given;
Fourth position is a flag that tells wether the data in the packet is complete or if it's to be compiled with data from other packets;
Fith and sixth positions are the LSB and MSB of the length of the data;
Seventh through Nth positions are for data;
(N+1)th is for the checksum [(sum through the N elements)&0xFF].
I know that I'm getting an error because when I get the response from the DLP the packet type is 1 (Error), and the data is coherent with error codes available on the documentation.
EDIT 2:
Issue solved, the problem was related to the variable types and not the socket.

Convert raw PCM to FLAC?

EDIT: I've updated the code below to resemble the progress I have made. I'm trying to write the .wav header myself. The code does not work properly as of now, the audio is not being written to the file properly. The code does not contain any attempts to convert it to a .flac file yet.
I am using a Raspberry Pi (Debian Linux) to record audio with the ALSA library. The recording works fine, but I need to encode the input audio into the FLAC codec.
This is where I get lost. I have spent a considerable amount of time trying to figure out how to convert this raw data into FLAC, but I keep coming up with examples of how to convert .wav files into .flac files.
Here is the current (updated) code I have for recording audio with ALSA (it may be a bit rough, I'm still picking up C++):
// Use the newer ALSA API
#define ALSA_PCM_NEW_HW_PARAMS_API
#include <alsa/asoundlib.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
struct Riff
{
char chunkId[4]; // "RIFF" (assuming char is 8 bits)
int chunkSize; // (assuming int is 32 bits)
char format[4]; // "WAVE"
};
struct Format
{
char chunkId[4]; // "fmt "
int chunkSize;
short format; // assuming short is 16 bits
short numChannels;
int sampleRate;
int byteRate;
short align;
short bitsPerSample;
};
struct Data
{
char chunkId[4]; // "data"
int chunkSize; // length of data
char* data;
};
struct Wave // Actual structure of a PCM WAVE file
{
Riff riffHeader;
Format formatHeader;
Data dataHeader;
};
int main(int argc, char *argv[])
{
void saveWaveFile(struct Wave *waveFile);
long loops;
int rc;
int size;
snd_pcm_t *handle;
snd_pcm_hw_params_t *params;
unsigned int sampleRate = 44100;
int dir;
snd_pcm_uframes_t frames;
char *buffer;
char *device = (char*) "plughw:1,0";
//char *device = (char*) "default";
printf("Capture device is %s\n", device);
/* Open PCM device for recording (capture). */
rc = snd_pcm_open(&handle, device, SND_PCM_STREAM_CAPTURE, 0);
if (rc < 0)
{
fprintf(stderr, "Unable to open PCM device: %s\n", snd_strerror(rc));
exit(1);
}
/* Allocate a hardware parameters object. */
snd_pcm_hw_params_alloca(&params);
/* Fill it in with default values. */
snd_pcm_hw_params_any(handle, params);
/* Set the desired hardware parameters. */
/* Interleaved mode */
snd_pcm_hw_params_set_access(handle, params, SND_PCM_ACCESS_RW_INTERLEAVED);
/* Signed 16-bit little-endian format */
snd_pcm_hw_params_set_format(handle, params, SND_PCM_FORMAT_S16_LE);
/* Two channels (stereo) */
snd_pcm_hw_params_set_channels(handle, params, 2);
/* 44100 bits/second sampling rate (CD quality) */
snd_pcm_hw_params_set_rate_near(handle, params, &sampleRate, &dir);
/* Set period size to 32 frames. */
frames = 32;
snd_pcm_hw_params_set_period_size_near(handle, params, &frames, &dir);
/* Write the parameters to the driver */
rc = snd_pcm_hw_params(handle, params);
if (rc < 0)
{
fprintf(stderr, "Unable to set HW parameters: %s\n", snd_strerror(rc));
exit(1);
}
/* Use a buffer large enough to hold one period */
snd_pcm_hw_params_get_period_size(params, &frames, &dir);
size = frames * 4; /* 2 bytes/sample, 2 channels */
buffer = (char *) malloc(size);
/* We want to loop for 5 seconds */
snd_pcm_hw_params_get_period_time(params, &sampleRate, &dir);
loops = 5000000 / sampleRate;
while (loops > 0)
{
loops--;
rc = snd_pcm_readi(handle, buffer, frames);
if (rc == -EPIPE)
{
/* EPIPE means overrun */
fprintf(stderr, "Overrun occurred.\n");
snd_pcm_prepare(handle);
} else if (rc < 0)
{
fprintf(stderr, "Error from read: %s\n", snd_strerror(rc));
} else if (rc != (int)frames)
{
fprintf(stderr, "Short read, read %d frames.\n", rc);
}
if (rc != size) fprintf(stderr, "Short write: wrote %d bytes.\n", rc);
}
Wave wave;
strcpy(wave.riffHeader.chunkId, "RIFF");
wave.riffHeader.chunkSize = 36 + size;
strcpy(wave.riffHeader.format, "WAVE");
strcpy(wave.formatHeader.chunkId, "fmt");
wave.formatHeader.chunkSize = 16;
wave.formatHeader.format = 1; // PCM, other value indicates compression
wave.formatHeader.numChannels = 2; // Stereo
wave.formatHeader.sampleRate = sampleRate;
wave.formatHeader.byteRate = sampleRate * 2 * 2;
wave.formatHeader.align = 2 * 2;
wave.formatHeader.bitsPerSample = 16;
strcpy(wave.dataHeader.chunkId, "data");
wave.dataHeader.chunkSize = size;
wave.dataHeader.data = buffer;
saveWaveFile(&wave);
snd_pcm_drain(handle);
snd_pcm_close(handle);
free(buffer);
return 0;
}
void saveWaveFile(struct Wave *waveFile)
{
FILE *file = fopen("test.wav", "wb");
size_t written;
if (file == NULL)
{
fprintf(stderr, "Cannot open file for writing.\n");
exit(1);
}
written = fwrite(waveFile, sizeof waveFile[0], 1, file);
fclose(file);
if (written < 1);
{
fprintf(stderr, "Writing to file failed, error %d.\n", written);
exit(1);
}
}
How would I go about converting the PCM data into the FLAC and save it to disk for later use? I have downloaded libflac-dev already and just need an example to go off of.
The way I am doing it right now:
./capture > test.raw // or ./capture > test.flac
The way it should be (program does everything for me):
./capture
If I understand the FLAC::Encoder::File documentation, you can do something like
#include <FLAC++/encoder.h>
FLAC::Encoder::File encoder;
encoder.init("outfile.flac");
encoder.process(buffer, samples);
encoder.finish();
where buffer is an array (of size samples) of 32-bit integer pointers.
Unfortunately, I know next to nothing about audio encoding so I can't speak for any other options. Good luck!
Please refer to the below code :
FLAC Encoder Test Code
This example is using a wav file as an input and then encodes it into FLAC.
As I understand, there is no major difference b/w WAV file and your RAW data, I think you can modify this code to directly read the "buffer" and convert it. You already have all the related information (Channel/Bitrate etc) so it should not be much of a problem to remove the WAV header reading code.
Please note: this is a modified version of the Flac Encoder sample from their git repo.
It includes some comments and hints on how to change it to OP's requirements, entire source for this will be a little bit long.
And do note that this is the C API, which tends to be a bit more complex than the C++ one. But it is fairly easy to convert between the two once you get the idea.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "share/compat.h"
#include "FLAC/metadata.h"
#include "FLAC/stream_encoder.h"
/* this call back is what tells your program the progress that the encoder has made */
static void progress_callback(const FLAC__StreamEncoder *encoder, FLAC__uint64 bytes_written, FLAC__uint64 samples_written, unsigned frames_written, unsigned total_frames_estimate, void *client_data);
#define READSIZE 1024
static unsigned total_samples = 0; /* can use a 32-bit number due to WAVE size limitations */
/* buffer is where we record to, in your case what ALSA writes to */
/* Note the calculation here to take the total bytes that the buffer takes */
static FLAC__byte buffer[READSIZE/*samples*/ * 2/*bytes_per_sample*/ * 2/*channels*/];
/* pcm is input to FLAC encoder */
/* the PCM data should be here, bps is 4 here...but we are allocating ints! */
static FLAC__int32 pcm[READSIZE/*samples*/ * 2/*channels*/];
int main(int argc, char *argv[])
{
FLAC__bool ok = true;
FLAC__StreamEncoder *encoder = 0;
FLAC__StreamEncoderInitStatus init_status;
FLAC__StreamMetadata *metadata[2];
FLAC__StreamMetadata_VorbisComment_Entry entry;
FILE *fin;
unsigned sample_rate = 0;
unsigned channels = 0;
unsigned bps = 0;
if((fin = fopen(argv[1], "rb")) == NULL) {
fprintf(stderr, "ERROR: opening %s for output\n", argv[1]);
return 1;
}
/* set sample rate, bps, total samples to encode here, these are dummy values */
sample_rate = 44100;
channels = 2;
bps = 16;
total_samples = 5000;
/* allocate the encoder */
if((encoder = FLAC__stream_encoder_new()) == NULL) {
fprintf(stderr, "ERROR: allocating encoder\n");
fclose(fin);
return 1;
}
ok &= FLAC__stream_encoder_set_verify(encoder, true);
ok &= FLAC__stream_encoder_set_compression_level(encoder, 5);
ok &= FLAC__stream_encoder_set_channels(encoder, channels);
ok &= FLAC__stream_encoder_set_bits_per_sample(encoder, bps);
ok &= FLAC__stream_encoder_set_sample_rate(encoder, sample_rate);
ok &= FLAC__stream_encoder_set_total_samples_estimate(encoder, total_samples);
/* sample adds meta data here I've removed it for clarity */
/* initialize encoder */
if(ok) {
/* client data is whats the progress_callback is called with, any objects you need to update on callback can be passed thru this pointer */
init_status = FLAC__stream_encoder_init_file(encoder, argv[2], progress_callback, /*client_data=*/NULL);
if(init_status != FLAC__STREAM_ENCODER_INIT_STATUS_OK) {
fprintf(stderr, "ERROR: initializing encoder: %s\n", FLAC__StreamEncoderInitStatusString[init_status]);
ok = false;
}
}
/* read blocks of samples from WAVE file and feed to encoder */
if(ok) {
size_t left = (size_t)total_samples;
while(ok && left) {
/* record using ALSA and set SAMPLES_IN_BUFFER */
/* convert the packed little-endian 16-bit PCM samples from WAVE into an interleaved FLAC__int32 buffer for libFLAC */
/* why? because bps=2 means that we are dealing with short int(16 bit) samples these are usually signed if you do not explicitly say that they are unsigned */
size_t i;
for(i = 0; i < SAMPLES_IN_BUFFER*channels; i++) {
/* THIS. this isn't the only way to convert between formats, I do not condone this because at first the glance the code seems like it's processing two channels here, but it's not it's just copying 16bit data to an int array, I prefer to use proper type casting, none the less this works so... */
pcm[i] = (FLAC__int32)(((FLAC__int16)(FLAC__int8)buffer[2*i+1] << 8) | (FLAC__int16)buffer[2*i]);
}
/* feed samples to encoder */
ok = FLAC__stream_encoder_process_interleaved(encoder, pcm, SAMPLES_IN_BUFFER);
left-=SAMPLES_IN_BUFFER;
}
}
ok &= FLAC__stream_encoder_finish(encoder);
fprintf(stderr, "encoding: %s\n", ok? "succeeded" : "FAILED");
fprintf(stderr, " state: %s\n", FLAC__StreamEncoderStateString[FLAC__stream_encoder_get_state(encoder)]);
FLAC__stream_encoder_delete(encoder);
fclose(fin);
return 0;
}
/* the updates from FLAC's encoder system comes here */
void progress_callback(const FLAC__StreamEncoder *encoder, FLAC__uint64 bytes_written, FLAC__uint64 samples_written, unsigned frames_written, unsigned total_frames_estimate, void *client_data)
{
(void)encoder, (void)client_data;
fprintf(stderr, "wrote %" PRIu64 " bytes, %" PRIu64 "/%u samples, %u/%u frames\n", bytes_written, samples_written, total_samples, frames_written, total_frames_estimate);
}

Winpcap saving raw packets not from an adapter

I am trying to build an application that converts my old custom Ethernet logs (bin files) to standard winpcap style logs.
The problem is that I can't seem to find an example of how to opening a pcap_t* without using an adapter (network card). The temp.pkt has not been created.
I have looked thou the examples provided with Winpcap and all of them use a live adapter when dumping packets. This example is the closest \WpdPack\Examples-pcap\savedump\savedump.c is the closest, see example below slightly modified.
#ifdef _MSC_VER
/*
* we do not want the warnings about the old deprecated and unsecure CRT functions
* since these examples can be compiled under *nix as well
*/
#define _CRT_SECURE_NO_WARNINGS
#endif
#include "pcap.h"
int main(int argc, char **argv)
{
pcap_if_t *alldevs;
pcap_if_t *d;
int inum;
int i=0;
pcap_t *adhandle;
char errbuf[PCAP_ERRBUF_SIZE];
pcap_dumper_t *dumpfile;
/* Open the adapter */
if ((adhandle= pcap_open(??????, // name of the device
65536, // portion of the packet to capture.
// 65536 grants that the whole packet will be captured on all the MACs.
1, // promiscuous mode (nonzero means promiscuous)
1000, // read timeout
errbuf // error buffer
)) == NULL)
{
fprintf(stderr,"\nUnable to open the adapter. %s is not supported by WinPcap\n", d->name);
/* Free the device list */
pcap_freealldevs(alldevs);
return -1;
}
/* Open the dump file */
dumpfile = pcap_dump_open(adhandle, argv[1]);
if(dumpfile==NULL) {
fprintf(stderr,"\nError opening output file\n");
return -1;
}
// ---------------------------
struct pcap_pkthdr header;
header.ts.tv_sec = 1 ; /* seconds */
header.ts.tv_usec = 1; /* and microseconds */
header.caplen = 100; /* length of portion present */
header.len = 100 ; /* length this packet (off wire) */
u_char pkt_data[100];
for( int i = 0 ; i < 100 ; i++ ) {
pkt_data[i] = i ;
}
pcap_dump( (u_char *) dumpfile, &header, (u_char *) &pkt_data);
// ---------------------------
/* start the capture */
// pcap_loop(adhandle, 0, packet_handler, (unsigned char *)dumpfile);
pcap_close(adhandle);
return 0;
}
I suggest doing that using pcap_t since using WinPcap is better than writing it yourself.
The following steps is how to do it:
Use pcap_open_dead() function to create a pcap_t. Read the function description here. The linktype for Ethernet is 1.
Use pcap_dump_open() function to create a pcap_dumper_t.
Use pcap_dump() function to write the packet to the dump file.
I hope this would help you.
If all you're doing is converting your own file format to .pcap, you don't need a pcap_t*, you can just use something like:
FILE* create_pcap_file(const char *filename, int linktype)
{
struct pcap_file_header fh;
fh.magic = TCPDUMP_MAGIC;
fh.sigfigs = 0;
fh.version_major = 2;
fh.version_minor = 4;
fh.snaplen = 2<<15;
fh.thiszone = 0;
fh.linktype = linktype;
FILE *file = fopen(filename, "wb");
if(file != NULL) {
if(fwrite(&fh, sizeof(fh), 1, file) != 1) {
fclose(file);
file = NULL;
}
}
return file;
}
int write_pcap_packet(FILE* file,size_t length,const unsigned char *data,const struct timeval *tval)
{
struct pcap_pkthdr pkhdr;
pkhdr.caplen = length;
pkhdr.len = length;
pkhdr.ts = *tval;
if(fwrite(&pkhdr, sizeof(pkhdr), 1, file) != 1) {
return 1;
}
if(fwrite(data, 1, length, file) != length) {
return 2;
}
return 0;
}