I'm Losin' It :(


M-.-n

Member
Joined
May 28, 2005
Messages
160
Location
Brussels, Belgium
Website
discodirt.10pm.org
Ok.. I'm having a hell of a trouble trying to make the sound driver of LGPT working for LGPT. I'm currently using /dev/dsp to feed audio buffers but the output is chopped. After watching the sound wave, I discovered that one block out of two is endian reversed ! Trying to dig what it was, I ended with this strange behavior:

First situation. I fill my pool buffer with a test saw wave just before copying it to the main sound buffer.

Code:
        short *input=(short *)pool_[poolPlayPosition_];
        for(int i=0;i<poolSize_[poolPlayPosition_]/4;i++) {
                short v=100*(i%100);
                input[i*2]=v;
                input[i*2+1]=v;
                
        }
        memcpy(mainBuffer_+bufferSize_-bufferPos_, pool_[poolPlayPosition_],poolSize_[poolPlayPosition_]);

If I do this, I get a chopped result, as below

fill_before_memcpy.JPG


Second. I copy the pool buffer but then overwrite the main buffer this time with a test triangle wave .

Code:
        memcpy(mainBuffer_+bufferSize_-bufferPos_, pool_[poolPlayPosition_],poolSize_[poolPlayPosition_]);
        
// Fill with fixed data

        short *input=(short *)mainBuffer_+bufferSize_-bufferPos_;
        for(int i=0;i<poolSize_[poolPlayPosition_]/4;i++) {
                short v=100*(i%100);
                input[i*2]=v;
                input[i*2+1]=v;
                
        }

now, altough the result should be the same, my output is fine

fill_after_memcpy.JPG


Does anybody see any sense in this ? Codewise, I don't see ANY reason for the two bits of code to be different.

FYI, the full driver code is here

Any help/tips more than welcome !!!
 
Looking in the rar archive, mainBuffer_ is a pointer to char, so the target address of the memcpy doesn't match the address pointed to by 'input' in the second example. In the memcpy call the arithmetic is done on pointer-to-char, while in the input assignment the arithmetic is done on pointer-to-short, so ends up out by a factor of two.

Casting mainBuffer_ in the memcpy call might resolve it.
 
I doubt it... memcpy's declaration is

void *memcpy(void *s1, const void *s2, size_t n);.

so working on void pointers and not doing arithmetics.... I'll give ur suggestion a try tho... just because I don't believe in anything anymore.
 
I've looked into this, had the same problem, and found the solution :)

When writing to /dev/dsp, the buffer MUST be half word aligned. This means that bit 0 of the address you pass to the write call MUST be zero (ie. the address is even).

So, if you provide sound data from a "char *" which happens to be on an odd address, OR you memcpy to an address which is odd, then you will get incorrect sound output.

This is due to the sound buffer reading an entire half word at a time from the sound buffer, and so if this buffer is misaligned, it reads incorrect data.

I've tested this by malloc'ing a buffer, filling it in with a sign-wave and playing it, and then shifting the contents of the buffer by one and playing it again. The first one plays fine, and the second one plays incorrectly.
 
Squidge posted on Mar 5 2006 at 11:55 PM said:
I've looked into this, had the same problem, and found the solution :)

Nice ;)

When writing to /dev/dsp, the buffer MUST be half word aligned. This means that bit 0 of the address you pass to the write call MUST be zero (ie. the address is even).

Ok.. got it. I'll see it it is my case.

So, if you provide sound data from a "char *" which happens to be on an odd address, OR you memcpy to an address which is odd, then you will get incorrect sound output.

I understand the driver could get confused by sending odd-boundary buffer address.. but how memcpy'ing *before* sending the buffer to the driver would influence the process if the mem boundary of the buffer in the write is always aligned ?

thanks squidgy !

 
Last edited by a moderator:
Reesy posted on Mar 6 2006 at 08:28 AM said:
Is this what causes the crackle in SquidgeSnes?

Doubt it, as I actually use a "unsigned short" array, so the compiler should align it for me.
 
Last edited by a moderator:
M-.-n posted on Mar 5 2006 at 08:48 PM said:
I doubt it... memcpy's declaration is

void *memcpy(void *s1, const void *s2, size_t n);.

so working on void pointers and not doing arithmetics.... I'll give ur suggestion a try tho... just because I don't believe in anything anymore.

The declaration is irrelevant - the maths is happening before the call. In this code, ptr1 and ptr2 will get different values, as will the two memcpy calls:

Code:
char *addr = 0x1000;

short *ptr1 = (short *)(addr + 128);  // = 0x1080
short *ptr2 = (short *)addr + 128;    // = 0x1100

memcpy(addr+128, source, count);          // same as writing to ptr1
memcpy((short *)addr+128, source, count); // same as writing to ptr2

More specifically to your code, in your second example the target address of the memcpy is not the same as the target address of the loop (what 'input' points at). That cast to (short*) in the initialization of the 'input' variable makes all the difference. Maybe there are other issues, I don't know anything about gp2x audio, but your did originally ask why the two code snippets would behave differently.
 
Last edited by a moderator:
gfoot posted on Mar 6 2006 at 09:05 PM said:
Code:
char *addr = 0x1000;

short *ptr1 = (short *)(addr + 128);  // = 0x1080
short *ptr2 = (short *)addr + 128;    // = 0x1100

memcpy(addr+128, source, count);          // same as writing to ptr1
memcpy((short *)addr+128, source, count); // same as writing to ptr2

Fuck me.. u'r too rite. I can't believe I've been programming for more than 30yrs thinking addition had precedence over casting .. this might explain my problem.

Ah.. well ; u learn every day :)

Thanks man !
 
Last edited by a moderator:
BODMAS!!!

Brackets, (power) Of, Division, Multiplication, Addition, Subtraction.



Other than SOHCAHTOA, that's one of the only things I remember from maths at school :p
 
Heh, BODMAS is only thing I've remembered too :) However, it doesn't seem to help me out much, as every time I decide to depend on it instead of using brackets, things seem to get evaluated wrong, as the person/people who wrote the software decided to use a different rule of precedence (which includes some commercial(!) compilers for embedded applications) So now I just bracketise everything.
 
I use () to force predictable evaluation too when forced to use infix notation. I prefer post- or prefix notation though.

When I was young, we learned to apply "meneer van dalen wacht op antwoord", which would be 'raise to the power' before 'multiplication' before 'division' before 'taking the root of' before 'addition' before 'subtraction'.

So these precedence things vary per country and also in time, because I don't think this order is being used anymore here, instead evaluation is from left to right, but multiplication and division go before addition and subtraction.

P.
 
Back
Top