I compiled the libe57 in order to use it in my project. I did it and now I'm trying to use it. (I'm on windows 10 x64)
Basing on this tutorial, I did this
int
main(int argc, char** argv)
{
char sFile[] = "PTX/file.e57";
_bstr_t bsFile = sFile; //converts Unicode to UTF-8
e57::Reader eReader((char*)bsFile);
e57::E57Root rootHeader;
eReader.GetE57Root(rootHeader);
const char* fileGuid = rootHeader.guid.c_str();
e57::DateTime fileGPSTime = rootHeader.creationDateTime;
int data3DCount = eReader.GetData3DCount();
int scanIndex = 0;
e57::Data3D scanHeader;
eReader.ReadData3D(scanIndex, scanHeader);
_bstr_t bstrName = scanHeader.name.c_str();
_bstr_t bstrGuid = scanHeader.guid.c_str();
_bstr_t bstrDesc = scanHeader.description.c_str();
int64_t nColumn = 0;
int64_t nRow = 0;
int64_t nPointsSize = 0; //Number of points
int64_t nGroupsSize = 0; //Number of groups
int64_t nCountSize = 0; //Number of points per group
bool bColumnIndex = false; //indicates that idElementName is "columnIndex"
eReader.GetData3DSizes(scanIndex, nRow, nColumn, nPointsSize, nGroupsSize, nCountSize, bColumnIndex);
int64_t nSize = nRow;
if (nSize == 0) nSize = 1024; // choose a chunk size
int8_t * isInvalidData = NULL;
if (scanHeader.pointFields.cartesianInvalidStateField)
isInvalidData = new int8_t[nSize];
double * xData = NULL;
if (scanHeader.pointFields.cartesianXField)
xData = new double[nSize];
double * yData = NULL;
if (scanHeader.pointFields.cartesianYField)
yData = new double[nSize];
double * zData = NULL;
if (scanHeader.pointFields.cartesianZField)
zData = new double[nSize];
double * intData = NULL;
bool bIntensity = false;
double intRange = 0;
double intOffset = 0;
if (scanHeader.pointFields.intensityField)
{
bIntensity = true;
intData = new double[nSize];
intRange = scanHeader.intensityLimits.intensityMaximum - scanHeader.intensityLimits.intensityMinimum;
intOffset = scanHeader.intensityLimits.intensityMinimum;
}
uint16_t * redData = NULL;
uint16_t * greenData = NULL;
uint16_t * blueData = NULL;
bool bColor = false;
int32_t colorRedRange = 1;
int32_t colorRedOffset = 0;
int32_t colorGreenRange = 1;
int32_t colorGreenOffset = 0;
int32_t colorBlueRange = 1;
int32_t colorBlueOffset = 0;
if (scanHeader.pointFields.colorRedField)
{
bColor = true;
redData = new uint16_t[nSize];
greenData = new uint16_t[nSize];
blueData = new uint16_t[nSize];
colorRedRange = scanHeader.colorLimits.colorRedMaximum - scanHeader.colorLimits.colorRedMinimum;
colorRedOffset = scanHeader.colorLimits.colorRedMinimum;
colorGreenRange = scanHeader.colorLimits.colorGreenMaximum - scanHeader.colorLimits.colorGreenMinimum;
colorGreenOffset = scanHeader.colorLimits.colorGreenMinimum;
colorBlueRange = scanHeader.colorLimits.colorBlueMaximum - scanHeader.colorLimits.colorBlueMinimum;
colorBlueOffset = scanHeader.colorLimits.colorBlueMinimum;
}
int64_t * idElementValue = NULL;
int64_t * startPointIndex = NULL;
int64_t * pointCount = NULL;
if (nGroupsSize > 0)
{
idElementValue = new int64_t[nGroupsSize];
startPointIndex = new int64_t[nGroupsSize];
pointCount = new int64_t[nGroupsSize];
if (!eReader.ReadData3DGroupsData(scanIndex, nGroupsSize, idElementValue,
startPointIndex, pointCount))
nGroupsSize = 0;
}
int32_t * rowIndex = NULL;
int32_t * columnIndex = NULL;
if (scanHeader.pointFields.rowIndexField)
rowIndex = new int32_t[nSize];
if (scanHeader.pointFields.columnIndexField)
columnIndex = new int32_t[nRow];
e57::CompressedVectorReader dataReader = eReader.SetUpData3DPointsData(
scanIndex, //!< data block index given by the NewData3D
nRow, //!< size of each of the buffers given
xData, //!< pointer to a buffer with the x data
yData, //!< pointer to a buffer with the y data
zData, //!< pointer to a buffer with the z data
isInvalidData, //!< pointer to a buffer with the valid indication
intData, //!< pointer to a buffer with the lidar return intesity
NULL,
redData, //!< pointer to a buffer with the color red data
greenData, //!< pointer to a buffer with the color green data
blueData, //!< pointer to a buffer with the color blue data
NULL,
NULL,
NULL,
NULL,
NULL,
rowIndex, //!< pointer to a buffer with the rowIndex
columnIndex //!< pointer to a buffer with the columnIndex
);
int64_t count = 0;
unsigned size = 0;
int col = 0;
int row = 0;
int cpt = 0;
while (size = dataReader.read())
{
cpt++;
}
std::cout << cpt << std::endl;
dataReader.close();
if (isInvalidData) delete isInvalidData;
if (xData) delete xData;
if (yData) delete yData;
if (zData) delete zData;
if (intData) delete intData;
if (redData) delete redData;
if (greenData) delete greenData;
if (blueData) delete blueData;
}
The problem is that everytime, the reader says that there are 65536 rows and 1 cols, meaning that my pointcloud contain always 65536 points. I tried with several files that have more than 200k points each, but the result are always the same, it writes in my XYZ file 65536 points, and no more.
EDIT 2: shorter example : the problem is still the same
#include "E57Foundation.h"
#include "E57Simple.h"
#include "comutil.h"
#include <iostream>
#include <vector>
int
main(int argc, char** argv)
{
e57::Reader eReader("PTX/file.e57");
int scanIndex = 0; //picking the first scan
e57::Data3D scanHeader; //read scan's header information
eReader.ReadData3D(scanIndex, scanHeader);
_bstr_t scanGuid = scanHeader.guid.c_str(); //get guid
int64_t nColumn = 0; //Number of Columns in a structure scan (from "indexBounds" if structure data)
int64_t nRow = 0; //Number of Rows in a structure scan
int64_t nPointsSize = 0; //Number of points
int64_t nGroupsSize = 0; //Number of groups (from "groupingByLine" if present)
int64_t nCountsSize = 0; //Number of points per group
bool bColumnIndex = false;
eReader.GetData3DSizes(scanIndex, nRow, nColumn, nPointsSize, nGroupsSize, nCountsSize, bColumnIndex);
int64_t nSize = (nRow > 0) ? nRow : 1024; //Pick a size for buffers
double *xData = new double[nSize];
double *yData = new double[nSize];
double *zData = new double[nSize];
e57::CompressedVectorReader dataReader = eReader.SetUpData3DPointsData(
scanIndex, //!< scan data index
nSize, //!< size of each of the buffers given
xData, //!< pointer to a buffer with the x data
yData, //!< pointer to a buffer with the y data
zData); //!< pointer to a buffer with the z data
//still a size of 65536
dataReader.close();
delete xData;
delete yData;
delete zData;
}
Related
I am trying to play a sin wave sound with SDL2 by using the audio queue on C++. In order to do that, I have created a class "Speaker", which has a pushBeep function that is called every time a beep needs to be generated. I have created an AudioDevice successfully, and it is also successful when I do the QueueAudio to the device (I have checked on the debugger) but I can't seem to get any sound out of it.
I have tried changing the way I generate the samples in numerous ways, also, as I said previously, I have checked that the device is properly opened and the QueueAudio returns 0 for success.
This is the class
Speaker::Speaker()
{
SDL_AudioSpec ds;
ds.freq = Speaker::SPEAKER_FREQUENCY;
ds.format = AUDIO_F32;
ds.channels = 1;
ds.samples = 4096;
ds.callback = NULL;
ds.userdata = this;
SDL_AudioSpec os;
this->dev = SDL_OpenAudioDevice(NULL, 0, &ds, &os, NULL);
std::cout << "DEVICE: " << this->dev << std::endl;
SDL_PauseAudioDevice(this->dev, 0);
}
Speaker::~Speaker()
{
SDL_CloseAudioDevice(this->dev);
}
void Speaker::pushBeep(double freq, int duration) {
int nSamples = duration * Speaker::SPEAKER_FREQUENCY / 1000;
float* samples = new float[nSamples];
double v = 0.0;
for (int idx = 0; idx < nSamples; idx++) {
//float value = (float)Speaker::SPEAKER_AMPLITUDE * std::sin(v * 2 * M_PI / Speaker::SPEAKER_FREQUENCY);
float value = 440.0;
samples[idx] = value;
v += freq;
}
int a = SDL_QueueAudio(this->dev, (void*)samples, nSamples * sizeof(float));
std::cout << a << std::endl;
delete[] samples;
samples = NULL;
}
And this is how I call it
Speaker s;
s.pushBeep(440.0, 1000);
When I try with the sin wave generation code (commented) it gives me a "double to float loss of precision" error. When I use the fixed value (not commented) it does not give the error, but it still does not work.
I expect the program to output the sound.
Couple of things you are missing, or maybe you didn't add to your code snippet. You didn't specify an audio callback so when you call SDL_QueueAudio(); it didn't know what to do with the data I'm pretty sure. And you weren't calling SDL_PauseAudioDevice() in your example with the delay.
#include <math.h>
#include <SDL2/SDL.h>
#include <SDL2/SDL_audio.h>
#include <iostream>
namespace AudioGen
{
const int AMPLITUDE = 1;
const int SAMPLE_RATE = 44000;
// Globals
float *in_buffer;
SDL_atomic_t callback_sample_pos;
SDL_Event event;
SDL_bool running = SDL_TRUE;
/**
* Structure for holding audio metadata such as frequency
*/
struct AudioData
{
int sampleNum;
float frequency;
};
void audio_callback(void *user_data, Uint8 *raw_buffer, int bytes)
{
float *buffer = (float*)raw_buffer;
AudioData &audio_data(*static_cast<AudioData*>(user_data));
int nSamples = bytes / 4; // For F32
std::cout << nSamples << std::endl;
for(int i = 0; i < nSamples; i++, audio_data.sampleNum++)
{
double time = (double)audio_data.sampleNum / (double)SAMPLE_RATE;
buffer[i] = (float)(AMPLITUDE * sin(2.0f * M_PI * audio_data.frequency * time));
}
}
int buffer_length;
void callback(void *user_data, Uint8 *raw_buffer, int bytes)
{
float *buffer = (float*)raw_buffer;
int nSamples = bytes/4;
auto local_sample_pos = SDL_AtomicGet(&callback_sample_pos);
for(int i = 0; i < nSamples; ++i)
{
// Stop running audio if all samples are finished playing
if(buffer_length == local_sample_pos)
{
running = SDL_FALSE;
break;
}
buffer[i] = in_buffer[local_sample_pos];
++local_sample_pos;
}
SDL_AtomicSet(&callback_sample_pos, local_sample_pos);
}
class Speaker
{
public:
Speaker()
{
SDL_Init(SDL_INIT_AUDIO);
SDL_AudioSpec ds;
ds.freq = SAMPLE_RATE;
ds.format = AUDIO_F32;
ds.channels = 1;
ds.samples = 4096;
ds.callback = callback;
ds.userdata = &ad; // metadata for frequency
SDL_AudioSpec os;
dev = SDL_OpenAudioDevice(NULL, 0, &ds, &os, SDL_AUDIO_ALLOW_FORMAT_CHANGE);
}
~Speaker()
{
SDL_CloseAudioDevice(dev);
SDL_Quit();
}
void pushBeep(float frequency, int duration)
{
ad.frequency = frequency; // set the frequency for the beep
SDL_PauseAudioDevice(dev, 0);
SDL_Delay(duration); // wait while sound is playing
SDL_PauseAudioDevice(dev, 1);
}
void pushBeep2(float frequency, int duration )
{
int nSamples = duration * SAMPLE_RATE / 1000;
in_buffer = new float[nSamples];
buffer_length = nSamples;
for (int idx = 0; idx < nSamples; idx++) {
double time = (double)idx / (double)SAMPLE_RATE;
in_buffer[idx] = (float)(AMPLITUDE * std::sin(2.0f * M_PI * frequency * time));
}
SDL_QueueAudio(dev, in_buffer, nSamples * sizeof(float));
SDL_PauseAudioDevice(dev, 0);
while(running){
while(SDL_PollEvent(&event)!=0);
}
delete[] in_buffer;
}
private:
SDL_AudioDeviceID dev;
AudioData ad;
int sampleNum = 0;
};
} // End of namespace AudioGen
int main(int argc, char *argv[])
{
AudioGen::Speaker speaker;
//speaker.pushBeep(440, 1000);
speaker.pushBeep2(440.0f, 1000);
return 0;
}
We have following method implemented using ijl15.lib API.
We want to use libjpeg libraries instead of ijl. How should I implement WriteJPGBuffer using libjpeg libraries? We are aware of LoadJPG and SaveJPG from file. However i want to write and read the jpg image in buffer using libjpeg libraries. Any inputs will be very helpul. Thank you in advance.
unsigned char WriteJPGBuffer(unsigned int &size)
{
size = 0;
int jErr;
JPEG_CORE_PROPERTIES jpgProps;
bool colorsSwapped;
if (!jpgSupported)
return NULL;
jErr = ijlInit(&jpgProps);
if (jErr != IJL_OK)
return NULL;
jpgProps.DIBWidth = m_width;
jpgProps.DIBHeight = -m_height;
jpgProps.DIBBytes = (unsigned char *)m_pData;
jpgProps.DIBPadBytes = 0 ;
jpgProps.DIBChannels = 4;
jpgProps.DIBColor = IJL_RGB;
jpgProps.JPGFile = NULL;
jpgProps.JPGWidth = m_width;
jpgProps.JPGHeight = m_height;
jpgProps.JPGChannels = 3;
jpgProps.JPGColor = IJL_YCBCR;
jpgProps.JPGSubsampling = IJL_411;
jpgProps.jquality = jpgQuality;
unsigned int iSize = m_width*m_height*3;
unsigned char * pBuffer = new unsigned char[iSize];
jpgProps.JPGSizeBytes = iSize;
jpgProps.JPGBytes = pBuffer;
jpgProps.jprops.jpeg_comment_size = (unsigned short)m_strCommentAdobe.length;
jpgProps.jprops.jpeg_comment = (char*)m_strCommentAdobe;
colorsSwapped = SetInternalFormat(RGB);
jErr = ijlWrite(&jpgProps, IJL_JBUFF_WRITEWHOLEIMAGE);
if (colorsSwapped)
SetInternalFormat(BGR);
if (jErr != IJL_OK)
{
ijlFree(&jpgProps);
return NULL;
}
size = jpgProps.JPGSizeBytes;
ijlFree(&jpgProps);
return jpgProps.JPGBytes;
}
Thanks for your inputs. I have implemented the solution below through RND. In below implementation, we have image data stored in the class member variable in the form of RGBQUAD which i am converting into unsigned char* first using ConversionfromGLRGBQUADToUnsignedChar function and then writing it jpeg buffer.
void ConversionfromGLRGBQUADToUnsignedChar(unsigned char* dataInCharFromGLRGBQUAD)
{
int spot,spotDst;
for (int y = 0;y < m_height;y++)
{
for (int x = 0;x<m_width;x++)
{
spot = y * m_width + x;
spotDst = spot * 3;
dataInCharFromGLRGBQUAD[spotDst] = m_pData[spot].red;
dataInCharFromGLRGBQUAD[spotDst + 1] = m_pData[spot].green;
dataInCharFromGLRGBQUAD[spotDst + 2] = m_pData[spot].blue;
}
}
}
unsigned char * WriteJPGBuffer(unsigned int &size)
{
size = 0;
struct jpeg_compress_struct cinfo;
struct jpeg_error_mgr jerr;
JSAMPROW row_pointer[1];
unsigned char* dataInCharFromGLRGBQUAD;
bool colorsSwapped;
int row_stride;
cinfo.err = jpeg_std_error(&jerr);
jpeg_create_compress(&cinfo);
unsigned long sizeOfJPGBuffer = 0;
jpeg_mem_dest(&cinfo, &m_pDIBData, &sizeOfJPGBuffer);
cinfo.image_width = m_width;
cinfo.image_height = m_height;
cinfo.input_components = 3;
cinfo.in_color_space = JCS_RGB;
cinfo.jpeg_color_space = JCS_YCbCr;
jpeg_set_defaults(&cinfo);
jpeg_set_quality(&cinfo, jpgQuality, true);
jpeg_start_compress(&cinfo, true);
colorsSwapped = SetInternalFormat(RGB);
FlipVert();
dataInCharFromGLRGBQUAD = new unsigned char[m_width*m_height*3];
ConversionfromGLRGBQUADToUnsignedChar(dataInCharFromGLRGBQUAD);
row_stride = cinfo.image_width * cinfo.input_components;
while (cinfo.next_scanline < cinfo.image_height)
{
row_pointer[0] = &dataInCharFromGLRGBQUAD[cinfo.next_scanline * row_stride];
jpeg_write_scanlines(&cinfo, row_pointer, 1);
}
if (colorsSwapped)
SetInternalFormat(BGR);
jpeg_finish_compress(&cinfo);
jpeg_destroy_compress(&cinfo);
size = sizeOfJPGBuffer;
delete[] dataInCharFromGLRGBQUAD;
return m_pDIBData;
}
Hi i am trying to record from a board and i have successfully record 4 seconds. Problem is when i try to record for more time, i got an error telling me that there not enough memory. my target is to record a 5 minutes file. Until now i have create a buffer named snIn[256] where are the samples. i send it to a big buffer of [16K * 4sec] and when it is full, i create the wav file.
#include "SAI_InOut.hpp"
#include "F746_GUI.hpp"
#include "Delay.hpp"
#include "WaveformDisplay.hpp"
#include "SDFileSystem.h"
#include "wavfile.h"
using namespace Mikami;
#define RES_STR_SIZE 0x20
#define WAVFILE_SAMPLES_PER_SECOND 16000
#define REC_TIME 4
//Create an SDFileSystem object
SDFileSystem sd("sd");
bool flag = 1;
int count = 0;
char *res_buf;
int rp = 0;
const int NUM_SAMPLES = WAVFILE_SAMPLES_PER_SECOND * REC_TIME;
Array<int16_t> my_buffer(NUM_SAMPLES);
int j = 0;
static const char *target_filename = "/sd/rectest.wav";
const int SEG_SIZE = 256;
int sent_array = 0;
int rec(const char *filename, Array<int16_t> my_buffer)
{
j = 0;
flag = 0;
sent_array = 0;
WavFileResult result;
wavfile_info_t info;
wavfile_data_t data;
WAVFILE_INFO_AUDIO_FORMAT(&info) = 1;
WAVFILE_INFO_NUM_CHANNELS(&info) = 1;
WAVFILE_INFO_SAMPLE_RATE(&info) = WAVFILE_SAMPLES_PER_SECOND;
WAVFILE_INFO_BITS_PER_SAMPLE(&info) = 16;
WAVFILE_INFO_BYTE_RATE(&info) = WAVFILE_INFO_NUM_CHANNELS(&info) * WAVFILE_INFO_SAMPLE_RATE(&info) * (WAVFILE_INFO_BITS_PER_SAMPLE(&info) / 8);
WAVFILE_INFO_BLOCK_ALIGN(&info) = 2;
WAVFILE *wf = wavfile_open(filename, WavFileModeWrite, &result);
if (result != WavFileResultOK) {
wavfile_result_string(result, res_buf, RES_STR_SIZE);
printf("%s", res_buf);
return result;
} else printf ("Open file success \r\n");
rp = 0;
WAVFILE_DATA_NUM_CHANNELS(&data) = 1;
result = wavfile_write_info(wf, &info);
if (result != WavFileResultOK) {
wavfile_result_string(result, res_buf, RES_STR_SIZE);
printf("%s", res_buf);
return result; } else printf ("Write info success \r\n");
while ( rp < NUM_SAMPLES ) {
WAVFILE_DATA_CHANNEL_DATA(&data, 0) = my_buffer[rp];
result = wavfile_write_data(wf, &data);
rp += 1;
}
if (result != WavFileResultOK) {
wavfile_result_string(result, res_buf, RES_STR_SIZE);
printf("%s", res_buf);
return result; } else printf ("Write Data file success \r\n");
result = wavfile_close(wf);
if (result != WavFileResultOK) {
wavfile_result_string(result, res_buf , RES_STR_SIZE);
printf("%s", res_buf);
return result; } else printf ("Close file success \r\n");
//UnMount the filesystem
sd.unmount();
printf("Success rec !\r\n");
return 0;
}
int main()
{
//Mount the filesystem
sd.mount();
const float MAX_DELAY = 0.5f; // 最大遅延,単位:秒
const int FS = I2S_AUDIOFREQ_16K; // 標本化周波数: 16 kHz
const uint32_t MAX_ARRAY_SIZE = (uint32_t)(MAX_DELAY*FS);
SaiIO mySai(SaiIO::BOTH, 256, FS, INPUT_DEVICE_DIGITAL_MICROPHONE_2);
Label myLabel(185, 10, "Delay System", Label::CENTER, Font16);
// ButtonGroup: "ON", "OFF"
const uint16_t BG_LEFT = 370;
const uint16_t BG_WIDTH = 100;
const uint16_t BG_HEIGHT = 45;
ButtonGroup onOff(BG_LEFT, 40, BG_WIDTH/2, BG_HEIGHT,
2, (string[]){"ON", "OFF"}, 0, 0, 2, 1);
const uint16_t SB_LEFT = BG_LEFT - 320;
const uint16_t SB_WIDTH = 270;
const uint16_t SB_Y0 = 240;
char str[20];
sprintf(str, " %3.1f [s]", MAX_DELAY);
SeekBar barDelay(SB_LEFT, SB_Y0, SB_WIDTH,
0, MAX_ARRAY_SIZE, 0, "0", "", str);
NumericLabel<float> labelDelay(SB_LEFT+SB_WIDTH/2, SB_Y0-40, "DELEY: %4.2f", 0, Label::CENTER);
DelaySystem delaySystem(MAX_ARRAY_SIZE);
WaveformDisplay displayIn(*GuiBase::GetLcdPtr(), SB_LEFT+7, 70, 256, 9,LCD_COLOR_WHITE, LCD_COLOR_CYAN,GuiBase::ENUM_BACK);
Label inLabel(SB_LEFT-30, 65, "IN");
WaveformDisplay displayOut(*GuiBase::GetLcdPtr(), SB_LEFT+7, 130, 256, 9,LCD_COLOR_WHITE, LCD_COLOR_CYAN,GuiBase::ENUM_BACK);
Label outLabel(SB_LEFT-30, 125, "OUT");
int runStop = 1;
Array<int16_t> snIn(mySai.GetLength());
Array<int16_t> snOut(mySai.GetLength());
mySai.RecordIn();
mySai.PlayOut();
mySai.PauseOut();
while (true)
{
// On/OFF
int num;
if (onOff.GetTouchedNumber(num))
if (runStop != num)
{
if (num == 0) mySai.ResumeOut();
else mySai.PauseOut();
runStop = num;
}
if (mySai.IsCompleted())
{
for (int n=0; n<mySai.GetLength() ; n++)
{
int16_t xL, xR;
mySai.Input(xL,xR);
int16_t xn = xL + xR;
snIn[n] = xn;
my_buffer[j] = xn;
j++;
if (j == NUM_SAMPLES && flag == 1) {
rec (target_filename , my_buffer); }
int16_t yn = delaySystem.Execute(xn);
mySai.Output(yn, yn);
snOut[n] = yn;
}
mySai.Reset();
displayIn.Execute(snIn);
}
}
}
I thought about a possible solution, to fill directly the "data field" of the wavefile with the snIn[256] buffer (instead of using my_buffer) again and again and at the end close the wavfile. Please let me know what you think about that and other solutions
things to note: 1) while a write operation is being performed, more data is still coming in.
At the very least I would double buffer that data, so can be writing one buffer while the other one fills.
Usually this means using an interrupt to collect the samples (into which ever buffer is currently being filed.)
the foreground program waits for the current buffer to be 'full', then initiates write operation.,
then waits again for a buffer to be 'full'
The interrupt function tracks which buffer is being filled and the current index into that buffer. When a buffer is full, set a 'global' status to let the foreground program know which buffer is ready to be written.
The foreground program writes the buffer, then resets the status for that buffer.
Im having a weird issue while initializing FMOD, FMOD enters in some kind of 'infinite loop' and the program stops. What i'm doing wrong?
This is the function:
FMOD::System *fmodsyst = 0;
FMOD::Sound *sound = 0;
FMOD::Channel *channel = 0;
FMOD_RESULT result = FMOD_OK;
unsigned int version = 0;
unsigned int soundlength = 0;
bool dspenabled = false;
void *extradriverdata = 0;
unsigned int recordpos = 0;
unsigned int recorddelta = 0;
unsigned int minrecorddelta = (unsigned int)-1;
unsigned int lastrecordpos = 0;
unsigned int samplesrecorded = 0;
unsigned int playpos = 0;
float smootheddelta = 0;
int recordrate = 0;
int recordchannels = 0;
unsigned int adjustedlatency = 0;
unsigned int driftthreshold = 0;
FMOD_CREATESOUNDEXINFO exinfo;
bool Basics::InitializeFMOD()
{
FMOD_RESULT result;
unsigned int version;
result = FMOD::System_Create(&fmodsyst);
FMOD_ERRCHECK(result);
result = fmodsyst->getVersion(&version);
FMOD_ERRCHECK(result);
if (version < FMOD_VERSION)
{
return false;
}
result = fmodsyst->init(100, FMOD_INIT_NORMAL, extradriverdata); //this is the line which crashes the .dll
FMOD_ERRCHECK(result);
result = fmodsyst->getRecordDriverInfo(0, NULL, NULL, 0, 0, &recordrate, 0, &recordchannels);
FMOD_ERRCHECK(result);
adjustedlatency = (recordrate * LATENCY_MS) / 1000;
driftthreshold = adjustedlatency / 2;
memset(&exinfo, 0, sizeof(FMOD_CREATESOUNDEXINFO));
exinfo.cbsize = sizeof(FMOD_CREATESOUNDEXINFO);
exinfo.numchannels = recordchannels;
exinfo.format = FMOD_SOUND_FORMAT_PCM16;
exinfo.defaultfrequency = recordrate;
exinfo.length = exinfo.defaultfrequency * sizeof(short)* exinfo.numchannels * 5; /* 5 second buffer, doesnt really matter how big this is, but not too small of course. */
result = fmodsyst->createSound(0, FMOD_LOOP_NORMAL | FMOD_OPENUSER, &exinfo, &sound);
FMOD_ERRCHECK(result);
result = fmodsyst->recordStart(0, sound, true);
FMOD_ERRCHECK(result);
result = sound->getLength(&soundlength, FMOD_TIMEUNIT_PCM);
FMOD_ERRCHECK(result);
return true;
}
Also the function FMOD_ERRCHECK doesnt say anything.
It might be that you want FMOD_STUDIO_INIT_NORMAL instead of FMOD_INIT_NORMAL because you are, in fact, initializing the Studio component and not the low level audio system (at least not via that pointer).
We may have different versions, as mine requires an extra parameter:
_pAudioSystem->initialize(32, FMOD_STUDIO_INIT_NORMAL, FMOD_INIT_NORMAL, nullptr);
I'm developing a project where I need to convert PCM 16-bits 2 channels sound into a IEEE Float 32-bits 2 channels.
To do this I'm using the following code:
void CAudioConverter::ConvI16ToF32(BYTE* pcmFrom, BYTE* floatTo, int length)
{
short* src = reinterpret_cast<short*>(pcmFrom);
float* dst = reinterpret_cast<float*>(floatTo);
for (int n = 0; n < length; n++)
{
dst[n] = static_cast<float>(src[n]) / 32768.0f;
}
}
I have initialized the variable __pcm32_bytesPerFrame with:
WAVEFORMATEX* closestFormat;
ws->default_pb_dev->GetMixFormat(&closestFormat);
__pcm32_bytesPerFrame = closestFormat->nAvgBytesPerSec * (prm->samples_per_frame * 1000 / (prm->clock_rate * closestFormat->nChannels)) / 1000;
strm->pb_max_frame_count is:
hr = ws->default_pb_dev->GetBufferSize(&ws->pb_max_frame_count);
I have a while loop in a dedicated thread the does something like:
hr = strm->default_pb_dev->GetCurrentPadding(&padding);
incoming_frame = __pcm32_bytesPerFrame / 4;
frame_to_render = strm->pb_max_frame_count - padding;
if (frame_to_render >= incoming_frame)
{
frame_to_render = incoming_frame;
} else {
/* Don't get new frame because there's no space */
frame_to_render = 0;
}
if (frame_to_render > 0)
{
pjmedia_frame frame;
hr = strm->pb_client->GetBuffer(frame_to_render, &cur_pb_buf);
if (FAILED(hr)) {
continue;
}
void* destBuffer = (void*)malloc(strm->bytes_per_frame*frame_to_render*sizeof(pj_uint16_t));
if (strm->fmt_id == PJMEDIA_FORMAT_L16) {
/* PCM mode */
frame.type = PJMEDIA_FRAME_TYPE_AUDIO;
frame.size = strm->bytes_per_frame;
frame.timestamp.u64 = strm->pb_timestamp.u64;
frame.bit_info = 0;
frame.buf = destBuffer;
}
status = (*strm->pb_cb)(strm->user_data, &frame);
CAudioConverter* conv = new CAudioConverter();
conv->ConvI16ToF32((BYTE*)destBuffer, cur_pb_buf, frame_to_render);
hr = strm->pb_client->ReleaseBuffer(frame_to_render, 0);
(...)
But, to send the sound to the WASAPI capture buffer I need a BYTE*.
How can I fill my 'floatTo' argument?
Any ideas?
Thanks
What about this:
void CAudioConverter::ConvI16ToF32(BYTE* pcmFrom, BYTE* floatTo, int length)
{
short* src = reinterpret_cast<short*>(pcmFrom);
float* dst = reinterpret_cast<float*>(floatTo);
for (int n = 0; n < length; n++)
{
dst[n] = static_cast<float>(src[n]) / 32768.0f;
}
}
Additionally make sure length indicates the number of elments in pcmFrom and floatTo, and not the number of bytes allocated. In you case pcmFrom should have allocated length*2 bytes and floatTo needs room for length*4 bytes.