fmod getWaveData() export to WAVE file help (C++)

eddietree
  • fmod getWaveData() export to WAVE file help (C++) eddietree

    I am trying to export the current sound that is being played by the FMOD::System into a WAVE file by calling getWaveData(). I have the header of the wave file correct, and currently trying to write to the wave file each frame like so:

    const unsigned int samplesPerSec = 48000;
    const unsigned int fps = 60;
    const int numSamples = samplesPerSec / fps;
    float data[2][numSamples];
    short conversion[numSamples*2];
    
    m_fmodsys->getWaveData( &data[0][0], numSamples, 0 ); // left channel
    m_fmodsys->getWaveData( &data[1][0], numSamples, 1 ); // right channel
    
    int littleEndian = IsLittleEndian();
    
    for ( int i = 0; i < numSamples; ++i )
    {
        // left channel
        float coeff_left = data[0][i];
        short val_left =  (short)(coeff_left * 0x7FFF);
    
        // right channel
        float coeff_right = data[1][i];
        short val_right =  (short)(coeff_right * 0x7FFF);
    
        // handle endianness
        if ( !littleEndian )
        {
            val_left = ((val_left & 0xff) << 8) | (val_left >> 8);
            val_right = ((val_right & 0xff) << 8) | (val_right >> 8);
        }
    
        conversion[i*2+0] = val_left;
        conversion[i*2+1] = val_right;
    }
    
    fwrite((void*)&conversion[0], sizeof(conversion[0]), numSamples*2, m_fh);
    m_dataLength += sizeof(conversion);
    

    Currently, the timing of the sound is correct, but the sample seems clipped way harshly. More specifically, I am outputting four beats in time. When I playback the wave-file, the beats timing is correct but it just sounds way fuzzy and clipped. Am I doing something wrong with my calculation?

    I am exporting in 16-bits, two channels.

    Thanks in advance! :)

    Reference (WAVE file format): http://www.sonicspot.com/guide/wavefiles.html

  • Your code makes sense to me.

    You should break this down into stages:

    1. Confirm the dynamic range of samples from getWaveData()
      Write each sample to a file as a string, then using somethign like Python or Octave (any tool that can read floats from a file, put them in some kind of vector, and then send that to the soundcard automatically) read your samples in and aurally confirm that FMOD itself is correct.

    2. Confirm your quantization step
      Having confirmed that sounds good, take the same data and read it into a C++ program that does the 16 bit quantization and again writes each sample out to a file as readable text.

      Now you can read that file in with Python, convert each int you read to a short in raw string format, and write that out to a sound file using the wave module. Play it back in your media player to confirm that it sounds good.

    Also maybe consider plotting the data so you can visually spot anomalies (like going outside of the -1 to 1.0 pre-quantization). If it sounds good at each of these stages, then maybe it's time to revisit how you wrote the WAVE header.

    Also agreed with Ray Dey, a compare/contrast soundfile would be helpful.

Tags
c++ fmod
Related questions and answers
  • _Commands, m_MD2Header.num_glcommands * sizeof(int)); // Read all the data. for(int i = 0; i &lt; m_MD2Header.num_frames; ++i) { md2_frame_t* Frame = (md2_frame_t*)&amp;Buffer[m_MD2Header.framesize * i]; vec3_t* Vertices = &amp;m_Vertices[m_MD2Header.num_xyz * i]; int* Normals = &amp;m_Normals[m_MD2Header.num_xyz * i]; for(int vertex = 0; vertex &lt...; int* m_Normals; unsigned int m_TextureID; float m_Scale; void Interpolate(vec3_t* Vertices); }; #include &lt;helpers/md2.h&gt; #include &lt;iostream> #include &lt

  • them. This is what I am trying to replace it with (in the exact same part of the program) int vCount = 0; for(int i = 0; i &lt; numTriangles; i++) { MD2Triangle* triangle = triangles + i...; Vec3f normal = v1-&gt;normal * (1 - frac) + v2-&gt;normal * frac; if (normal[0] == 0 &amp;&amp; normal[1] == 0 &amp;&amp; normal[2] == 0) { normal = Vec3f(0, 0, 1... at the same time: glBegin(GL_TRIANGLES); for(int i = 0; i &lt; numTriangles; i++) { MD2Triangle* triangle = triangles + i; for(int j = 0; j &lt; 3; j++) { MD2Vertex* v1

  • , In); // Get The Current Line ( NEW ) shaderData[i][0] = shaderData[i][1] = shaderData[i][2] = float(atof (Line)); // Copy Over The Value ( NEW ) } fclose... &lt; numTriangles; i++) { MD2Triangle* triangle = triangles + i; for(int j = 0; j &lt; 3; j++) { MD2Vertex* v1 = frame1-&gt;vertices + triangle-&gt;vertices[j... = triangles + i; for(int j = 0; j &lt; 3; j++) { MD2Vertex* v1 = frame1-&gt;vertices + triangle-&gt;vertices[j]; MD2Vertex* v2 = frame2-&gt;vertices + triangle-&gt;vertices[j

  • }; // for the old/new screen command // Some nCurses setup int r = 0, c = 0; // current row and column (upper-left is (0,0)) const int nrows = 56, // number of rows in window ncols = 79...--; cspace++;}} for(int s= 0; s &lt;sspace; s++) buff[buff.size()-1].push_back(' '); // cwall2 //if(cwall2!= 0){ // if(cwall2&gt;0... GeneratePath( vector<string>&amp; buff){// the buff is the seed too int wall= RandNumb(80)/2, space = (RandNumb(75)/2)+5, wall2= 80-(space+wall); int swall= 0

  • the viewport data ZeroMemory(&amp;viewport, sizeof(D3D10_VIEWPORT)); // clear out the struct for use viewport.TopLeftX = 0; // set the left to 0 viewport.TopLeftY = 0; // set the top to 0... memcpy(pVoid, OurVertices, sizeof(OurVertices)); // copy the vertices to the buffer pBuffer-&gt;Unmap(); // create the index buffer out of DWORDs DWORD OurIndices[] = { 0, 1, 2, // side 1... sorry if it's in the wrong place. SORRY IN ADVANCE FOR THE AMOUNT OF CODE! file that makes the calls: #include &lt;d3d10.h&gt; #include &lt;d3dx10.h&gt; #include "direct3D.h" #include "game.h

  • : float m_Position[3]; // x, y, z // offset 0, size = 3*sizeof(float) float m_TexCoords[2]; // u, v // offset 3*sizeof(float), size = 2*sizeof(float) float m_Normal[3... in the shader code) for( int n = 0; n &lt; vShaderArgs.size(); n ++) glBindAttribLocation( m_nProgramId, n, vShaderArgs[n].sFieldName.c_str() ); // Create and bind to a vertex array object, which..._TRIANGLES, m_nNumIndices, GL_UNSIGNED_INT, ((char*)NULL + 0) ); glDisableClientState( GL_VERTEX_ARRAY ); glDisableClientState( GL_TEXTURE_COORD_ARRAY ); glDisableClientState( GL_NORMAL_ARRAY

  • (); missile-&gt;Init(true, s-&gt;X, s-&gt;Y); bullets-&gt;push_back(missile); } } void CleanUp() { for(unsigned int index = 0; index &lt; bullets-&gt;size(); index++) { if (bullets-&gt;at(index)-&gt;Alive == false) { bullets-&gt;erase(bullets-&gt;begin() + index); } } } void UpdateBullets() { for(unsigned int index = 0; index &lt...;at(index)-&gt;Kill(); } } } void DrawBullets(BITMAP* buffer, BITMAP* sprite) { for(unsigned int index = 0; index &lt; bullets-&gt;size(); index++) { if (bullets-&gt;at(index

  • ] -= ball.xspeed; ballPrev.coords[3] -= ball.yspeed; int up = 0; int left = 0; int right = 0; int down = 0; if (ballPrev.coords[0] &lt; block[i].coords[0] &amp;&amp; ballPrev.coords[2] &lt; block[i].coords[0] &amp;&amp; (((ball.coords[1] &lt; block[i].coords[1]) || (ball.coords[3] &lt; ball.coords[1])) || ((ball.coords[1] &lt; block[i].coords[3]) || ball.coords[3] &lt; block[i].coords[3]))) { left = 1; } if (ballPrev.coords[0] &gt; block[i].coords[2] &amp;&amp; ballPrev.coords[2] &gt; block[i].coords[2] &amp;&amp

  • )Point[0], (float)Point[1], (float)Point[2])); // set rotation btVector3 EulerRotation; QuaternionToEuler(TObject-&gt;getOrientation(), EulerRotation); node-&gt;setOrientation(1,(Ogre... = TObject-&gt;getCenterOfMassPosition(); node-&gt;setPosition(Ogre::Vector3((float)Point[0], (float)Point[1], (float)Point[2])); // Convert the bullet Quaternion to an Ogre quaternion... every frame to handle input and render etc I call an UpdatePhysics method to update the physics simulation. void GameState::UpdatePhysics(unsigned int TDeltaTime) { World-&gt;stepSimulation(TDeltaTime

Data information