0
0

Hi there.

I am programming a tiny DLL that I can use FMOD (playing mp3-streams, recording and saving wav-samples) through J2ME on my handheld via JNI. Thanks to the examples and great documentation, I managed that, though I’m not really a C++-expert. ๐Ÿ˜‰

The DLL is working fine, but I have a problem though. When I am saving the recorded data to a wave-file, the wave seems to be somewhat corrupt. When I play it in WinAMP, it’s playing only half of the recorded data. So: I have recorded 20 seconds, but it’s playing 10 of it. And: Other programs like WindowsMediaPlayer say, that the file is corrupt and do not want to play it.

Can you help me with that? I think the problem should be in the methods ‘WriteWAVHeader’ or ‘fmod_save_sample’.

I am posting the whole code, so that other people may take it as an example or use it themselves. I know it’s not really well coded, but it’s fitting my needs. ๐Ÿ˜ณ

[code:199u90w0]#include <jni.h>

include "stdafx.h"

include <cstdio>

include <stdlib.h>

if defined(WIN32) || defined(WATCOMC) || defined(_WIN32) || defined(WIN32)

#include &lt;windows.h&gt;
#define __PACKED /*dummy*/

else

#include &lt;string.h&gt;
#define __PACKED __attribute__((packed)) /* gcc packed */

endif

include "util_SoundRec.h"

include <fmodce.h>

FSOUND_STREAM *stream;
FSOUND_SAMPLE *sample;
bool recordMode, playMode;
bool FAILED_INIT = false;
int position = 0;
int lastrecordpos = 0;
int rate = 22050;

/*
* Method: writeWAVHeader
* Task: Saving the header for the WAVE-File.
* Parameter: *FILE – Filepointer
* int – Length of the WAVE-Data in Samples
* Return: – none –
*/
void writeWAVHeader(FILE *fp) {

unsigned int    mode     = FSOUND_Sample_GetMode(sample);
int             bits     = (mode &amp; FSOUND_16BITS) ? 16 : 8;
int             channels = (mode &amp; FSOUND_STEREO) ? 2  : 1;
int             lenbytes = lastrecordpos * channels * bits / 8;
FSOUND_Sample_GetDefaults(sample, &amp;rate, 0, 0, 0); 

fseek(fp, 0, SEEK_SET);

// WAV Structures
typedef struct {
    signed   char       id[4];
    int                 size;
} RiffChunk;

#pragma pack(1)

struct {
    RiffChunk           chunk;
    unsigned short      wFormatTag;
    unsigned short      nChannels;
    unsigned int        nSamplesPerSec;
    unsigned int        nAvgBytesPerSec;
    unsigned short      nBlockAlign;
    unsigned short      wBitsPerSample;
} FmtChunk  = { {{'f','m','t',' '}, sizeof(FmtChunk) - sizeof(RiffChunk) }, 1, channels, rate, rate * channels * bits / 8, 1 * channels * bits / 8, bits };

struct {
    RiffChunk           chunk;
} DataChunk = { {{'d','a','t','a'}, lenbytes } };

struct {
    RiffChunk           chunk;
    signed char         rifftype[4];
} WavHeader = { {{'R','I','F','F'}, sizeof(FmtChunk) + sizeof(RiffChunk) + lenbytes }, {'W','A','V','E'} };

#pragma pack()

// Write out the WAV header.
fwrite(&amp;WavHeader, sizeof(WavHeader), 1, fp);
fwrite(&amp;FmtChunk, sizeof(FmtChunk), 1, fp);
fwrite(&amp;DataChunk, sizeof(DataChunk), 1, fp);

}

/*
* Class: util_SoundRec
* Method: fmod_init
* Signature: ()Z
* Task: Initialisierung des Sound-Moduls FMOD
* Parameter: – keine –
* Return: TRUE – Erfolgreich
* FALSE – Nicht erfolgreich
*/
JNIEXPORT jboolean JNICALL Java_util_SoundRec_fmod_1init( JNIEnv *env, jclass clazz ) {

// Trying to initialise sound-hardware
int retrycount = 0;
while (!FSOUND_Init(rate, 8, FSOUND_INIT_GLOBALFOCUS) &amp;&amp; retrycount &lt; 10) {
    Sleep(100);
    retrycount++;
}
if (retrycount == 10) {
    /* Print error */
    FAILED_INIT = true;
}

return (jboolean)!FAILED_INIT;

}

/*
* Class: util_SoundRec
* Method: fmod_record_start
* Signature: ()Z
* Task: Starting the record
* Parameter: – none –
* Return: TRUE – OK
* FALSE – Could not create the sample
*/
JNIEXPORT jboolean JNICALL Java_util_SoundRec_fmod_1record_1start( JNIEnv *env, jclass clazz ) {

sample = FSOUND_Sample_Alloc(1, rate*60, FSOUND_MONO | FSOUND_8BITS, rate, 255, 128, 255);
if (!sample) {
    return (jboolean)false;
} else {
    FSOUND_Record_StartSample(sample, FALSE);
    recordMode = true;
    return (jboolean)true;
}

}

/*
* Class: util_SoundRec
* Method: fmod_record_stop
* Signature: ()I
* Task: Stopping the record
* Parameter: – none –
* Return: Length of the recording in samples or -1 when not in record-mode
*/
JNIEXPORT jint JNICALL Java_util_SoundRec_fmod_1record_1stop( JNIEnv *env, jclass clazz ) {

if ( recordMode ) {
    lastrecordpos = FSOUND_Record_GetPosition();
    FSOUND_Record_Stop();
    return (jint)lastrecordpos;
} else {
    return (jint)-1;
}

}

/*
* Class: util_SoundRec
* Method: fmod_save_sample
* Signature: ()Z
* Task: Saving the record in \record.wav
* Parameter: – none –
* Return: TRUE – OK
* FALSE – Could not create the file or not in record-mode
*/
JNIEXPORT jboolean JNICALL Java_util_SoundRec_fmod_1save_1sample( JNIEnv *env, jclass clazz ) {

if ( !recordMode ) {
    return (jboolean)false;
}

FILE            *fp;
void            *ptr1, *ptr2;
int             datalength = 0;
unsigned int    len1, len2;

fp = fopen(&quot;\\record.wav&quot;, &quot;wb&quot;);
if (!fp) {
    return (jboolean)false;
}

writeWAVHeader( fp );
FSOUND_Sample_Lock( sample, 0, lastrecordpos, &amp;ptr1, &amp;ptr2, &amp;len1, &amp;len2 );

if (ptr1 &amp;&amp; len1) {
    datalength += fwrite(ptr1, 1, len1, fp);
}
if (ptr2 &amp;&amp; len2) {
    datalength += fwrite(ptr2, 1, len2, fp);
}

FSOUND_Sample_Unlock( sample, ptr1, ptr2, len1, len2);

fclose(fp);

return (jboolean)true;

}

/*
* Class: util_SoundRec
* Method: fmod_play
* Signature: (Ljava/lang/String;)I
* Task: When in record-mode: Play the recorded sample
Otherwise: Load the file and play it as a stream
* Parameter: jstring – Filename
* Return: jint – Errorcode as in FSOUND_Stream_GetOpenState or 0 for success
*/
JNIEXPORT jint JNICALL Java_util_SoundRec_fmod_1play( JNIEnv *env, jclass clazz, jstring string) {

if ( recordMode ) {
    FSOUND_PlaySound( FSOUND_FREE, sample );
    return (jint)0;     
} else {      
    int             channel;

    // Java String in C-String konvertieren und an C-Variable zuweisen
    const char *c_string = env-&gt;GetStringUTFChars(string, NULL);

    stream = FSOUND_Stream_Open( c_string, FSOUND_LOOP_OFF, 0, 0 );
    int openstate = FSOUND_Stream_GetOpenState( stream );
    if (openstate != 0) {
        return (jint)openstate;
    } else {
        channel = FSOUND_Stream_Play( FSOUND_FREE, stream );
        playMode = true;
        return (jint)0;
    }
}  

}

/*
* Class: util_SoundRec
* Method: fmod_pause
* Task: When in play-mode: Pausing the stream
* Otherwise: Returning FALSE
* Parameter: – none –
* Return: TRUE – OK
* FALSE – Not successful or in record-mode
* Signature: ()Z
*/
JNIEXPORT jboolean JNICALL Java_util_SoundRec_fmod_1pause( JNIEnv *env, jclass clazz ) {

if ( recordMode ) {
    return (jboolean)false;
} else {
    position        = FSOUND_Stream_GetTime( stream );
    bool success    = FSOUND_Stream_Stop( stream );
    return (jboolean)success;
}

}

/*
* Class: util_SoundRec
* Method: fmod_resume
* Task: When in play-mode: Resuming the stream
* Parameter: – none –
* Return: -1 – Not successful or in record-mode
* channel > 0 – Channel, which is playing the stream
* Signature: ()I
*/
JNIEXPORT jint JNICALL Java_util_SoundRec_fmod_1resume( JNIEnv *env, jclass clazz ) {

if ( recordMode ) {
    return (jboolean)-1;
} else {
    bool success = FSOUND_Stream_SetTime( stream, position );
    if ( success ) {
        int channel = FSOUND_Stream_Play( FSOUND_FREE, stream );
        return (jint)channel;
    } else {
        return (jint)-1;
    }
}

}

/*
* Class: util_SoundRec
* Method: fmod_stop
* Signature: ()Z
* Task: When in record-mode: Stop playing of the recorded sample
* Otherwise: Stop playing the stream
* Parameter: – none –
* Return: TRUE – OK
* FALSE – Not successful
*/
JNIEXPORT jboolean JNICALL Java_util_SoundRec_fmod_1stop ( JNIEnv *env, jclass clazz ) {

if ( recordMode ) {
    bool success = FSOUND_StopSound( FSOUND_ALL );
    return (jboolean)success;
} else {
    bool success = FSOUND_Stream_Stop( stream );
    if (success) {
        position = 0;
        success = FSOUND_Stream_SetPosition( stream, 0);
    }
    return (jboolean)success;
}

}

/*
* Class: util_SoundRec
* Method: fmod_jump
* Signature: (I)Z
* Task: Jump to the delivered position in ms
* Parameter: jint – Position in ms
* Return: TRUE – OK
* FALSE – Not successful
*/
JNIEXPORT jboolean JNICALL Java_util_SoundRec_fmod_1jump ( JNIEnv *env, jclass clazz, jint ms ) {

bool success = FSOUND_Stream_SetTime( stream, ms );
position = ms;
return (jboolean)success;

}

/*
* Class: util_SoundRec
* Method: fmod_getStreamLength
* Signature: ()I
* Task: When in play-mode: Returning the length of the stream in ms or bytes
* Otherwise: 0
* Parameter: jboolean – true – ms; false – bytes
* Return: jint – Length
*/
JNIEXPORT jint JNICALL Java_util_SoundRec_fmod_1getStreamLength( JNIEnv *env, jclass clazz, jboolean ms) {

if ( recordMode ) 
    return (jint)0;
if (ms) {
    return (jint)FSOUND_Stream_GetLengthMs( stream );
} else {
    return (jint)FSOUND_Stream_GetLength( stream );
}

}

/*
* Class: util_SoundRec
* Method: fmod_getStreamPosition
* Signature: ()I
* Task: When in play-mode: Returning the position of the play-cursor in ms or bytes
* Otherwise: 0
* Parameter: jboolean – true – ms; false – bytes
* Return: jint – Position
*/
JNIEXPORT jint JNICALL Java_util_SoundRec_fmod_1getStreamPosition( JNIEnv *env, jclass clazz, jboolean ms) {

if ( recordMode ) 
    return (jint)0;
if (ms) {
    return (jint)FSOUND_Stream_GetTime( stream );
} else {
    return (jint)FSOUND_Stream_GetPosition( stream );
}

}

/*
* Class: util_SoundRec
* Method: fmod_close
* Signature: ()Z
* Task: Closing FMOD and quitting
* Parameter: – none –
* Return: TRUE – OK
* FALSE – Not successful
*/
JNIEXPORT jboolean JNICALL Java_util_SoundRec_fmod_1close( JNIEnv *env, jclass clazz ) {

bool success = true;
if ( FSOUND_Stream_GetOpenState( stream ) == 0 ) {
    success = FSOUND_Stream_Close( stream );
}
if ( success ) {
    recordMode = false;
    playMode   = false;
    FSOUND_Close();
}
return (jboolean)success;

}
[/code:199u90w0]

  • You must to post comments
0
0

I would just make sure that #pragma pack() is working

  • You must to post comments
0
0

Hmm, I have stripped writeWAVHeader down to this now:

[code:2wb5kjw9]void writeWAVHeader(FILE *fp, int length) {

fseek(fp, 0, SEEK_SET);

/*
    WAV Structures
*/
struct {
    signed   char   id[4];                  // 'fmt ' 
    unsigned int    size;                   // size of FmtChunk without size and id (16 bytes) 
    unsigned short  wFormatTag;             // format type  
    unsigned short  nChannels;              // number of channels (i.e. mono, stereo...)  
    unsigned int    nSamplesPerSec;         // sample rate  
    unsigned int    nAvgBytesPerSec;        // for buffer estimation  
    unsigned short  nBlockAlign;            // block size of data  
    unsigned short  wBitsPerSample;         // number of bits per sample of mono data 
} FmtChunk  = { {'f','m','t',' '}, 16, 1, channels, rate, rate * channels * bits / 8, 1 * channels * bits / 8, bits };

struct {
    signed   char   id[4];                  // 'data' 
    unsigned int    size;                   // size of DataChunk 
} DataChunk = { {'d','a','t','a'}, length };

struct {
    signed   char   id[4];                  // 'RIFF' 
    unsigned int    size;                   // size of RiffChunk 
    signed   char   rifftype[4];            // 'WAVE' 
} RiffChunk = { {'R','I','F','F'}, sizeof(FmtChunk) + length, {'W','A','V','E'} };

// Write out the WAV header.
fwrite(&amp;RiffChunk, sizeof(RiffChunk), 1, fp);
fwrite(&amp;FmtChunk, sizeof(FmtChunk), 1, fp);
fwrite(&amp;DataChunk, sizeof(DataChunk), 1, fp);

}[/code:2wb5kjw9]

But the result is nearly the same though. When I record 10 secs, WinAMP still plays 5 of it. But WindowsMediaPlayer shows an error-message ‘Corrupt’, plays 4 seconds of it and then stops….

  • You must to post comments
0
0

eh? i said make sure pragma pack is working so you deleted it? That just makes -sure- it is broken. It is there for a purpose, to make sure the char is stored as a char and not padded out to a dword.

  • You must to post comments
0
0

Kay. I read some things about it that it isn’t supported on some platforms and that it’s used to save the data contiguos without any memory holes. So I thought I could delete it.

I’m looking today, if it’s working or not. But is there a another possibility to save the data correctly without using pragma pack? It would be better on handhelds I presume.

  • You must to post comments
0
0

Hmm, when I set the bits to 8 (rate still on 22050 and mono) and save the recorded data, all is well on that side. WinAMP and WindowsMediaPlayer are playing the resulting file correctly. But then I have another problem: When I play the recorded data with FSOUND_PlaySound before saving, the output is really noisy as if the record is totally overdriven. But as I said, when I save it to a file, it is played well on the desktop. ๐Ÿ˜ฎ

I have not been able to find out yet, if pragma pack is working. But if I knew why the output is distorted, I’d be happy as well, because the saving is working now…. all I do is calling

  • fmod_init
  • fmod_record_start
  • fmod_record_stop
  • fmod_play
  • You must to post comments
0
0

One easy way to know if pragma pack is working is to check what sizeof() returns for all your structures. If it’s the sum of the sizes of all the fields in the structure then it’s working fine.

If you don’t want to use pragma pack, you can write the data on a field basis instead of a structure basis.

  • You must to post comments
Showing 6 results
Your Answer

Please first to submit.