flat assembler
Message board for the users of flat assembler.

Index > Heap > Combining two wave files.

Author
Thread Post new topic Reply to topic
kohlrak



Joined: 21 Jul 2006
Posts: 1421
Location: Uncle Sam's Pad
kohlrak
I have been wondering for a short time how to combine two wave files. Theoretically, if you have two wave files of the same size and bitrate, you could simply or them together and it would merge as if both sounds happened at the same time. Well, my theory was obviously wrong. It worked to a point. It sounds like it was thrown through a paper shreader before being played. Interestingly enough, i tried with XOR and AND, while XOR wouldn't play, the AND was seemingly more accurate than OR.

Maybe if i could figure out how to make one wave a left speaker sound and the other a right speaker sound, it might work. Because this project is now making me rather interested, does anyone have any ideas?
Post 09 Feb 2007, 04:49
View user's profile Send private message Visit poster's website AIM Address Yahoo Messenger MSN Messenger Reply with quote
Octavio



Joined: 21 Jun 2003
Posts: 366
Location: Spain
Octavio
A sample in a wav file is just a unsigned number, first you must convert it in signed number changing the high bit like xor ax,8000h for 16bit sample then add two samples ,divide by 2 and convert again to unsigned, thats all.
Post 09 Feb 2007, 05:24
View user's profile Send private message Visit poster's website Reply with quote
kohlrak



Joined: 21 Jul 2006
Posts: 1421
Location: Uncle Sam's Pad
kohlrak
and for making non-mono files? Do we just change one of the bytes and then every other byte is one channel and the next byte is the following?

EDIT: well, that worked alot better, but now the static went high to the point of pure hostility to one's hears.
Post 09 Feb 2007, 11:41
View user's profile Send private message Visit poster's website AIM Address Yahoo Messenger MSN Messenger Reply with quote
f0dder



Joined: 19 Feb 2004
Posts: 3170
Location: Denmark
f0dder
kohlrak wrote:

while XOR wouldn't play, the AND was seemingly more accurate than OR.

XOR wouldn't play? Did you just XOR all the file data of two .wav files, thereby destroying the headers? Or did you just XOR the wave data?

Anyway, sound can come in a lot of formats. Even for a .wav file, there are a lot of possibilities, since a .wav file is just a container. The most common format is 44.1KHz 16bit unsigned stereo, but there's signed/unsigned, 8/16bit and even floating-point formats, 44.8KHz and 96KHz are also possible, mono/stereo (and even multi-channels like DTS, AC3, blablabla), and then there's various codecs rather than just raw PCM.
Post 09 Feb 2007, 12:08
View user's profile Send private message Visit poster's website Reply with quote
kohlrak



Joined: 21 Jul 2006
Posts: 1421
Location: Uncle Sam's Pad
kohlrak
Quote:
XOR wouldn't play? Did you just XOR all the file data of two .wav files, thereby destroying the headers? Or did you just XOR the wave data?


Destroyed the headers, i got too lazy to try to preserve them. lol

Quote:
Anyway, sound can come in a lot of formats. Even for a .wav file, there are a lot of possibilities, since a .wav file is just a container. The most common format is 44.1KHz 16bit unsigned stereo, but there's signed/unsigned, 8/16bit and even floating-point formats, 44.8KHz and 96KHz are also possible, mono/stereo (and even multi-channels like DTS, AC3, blablabla), and then there's various codecs rather than just raw PCM.


Yay, guess this is a time to go in with the "wave editor" program and convert to ".raw" and see if that works. lol

EDIT: Didn't change anything. The resulting waveform looks rather intresting, though. I'll have to finish this another time with the help of some more in depth documents on ADPCM format (so perhaps i could read the headers to decide what to do with it, cause right now i'm just guessing on the bitrate and such).
Post 09 Feb 2007, 12:11
View user's profile Send private message Visit poster's website AIM Address Yahoo Messenger MSN Messenger Reply with quote
f0dder



Joined: 19 Feb 2004
Posts: 3170
Location: Denmark
f0dder
Duh, no wonder you've gotten weird results, then Wink

Handling (standard) wavefiles isn't a big deal, really, but working on raw certainly is that slight bit easier.
Post 09 Feb 2007, 12:20
View user's profile Send private message Visit poster's website Reply with quote
kohlrak



Joined: 21 Jul 2006
Posts: 1421
Location: Uncle Sam's Pad
kohlrak
I'm pretty sure it's 16 bit though, i'm using C++ rather than reading up on file I/O for ASM (havn't had the time), so maybe it's my calculations. Because this is just a simple unreleased project of mine, it's not really important enough to me to make it run faster.

Code:
#include "stdafx.h"

FILE *stream1;
FILE *stream2;
FILE *stream3;

int main(int argc, char* argv[])
{
        int count=0;
        char string1[]="file1.raw";
        char string2[]="file2.raw";
        char string3[]="file3.raw";
        stream1=fopen(string1,"rb");
        stream2=fopen(string2,"rb");
        stream3=fopen(string3,"wb");
        while(!feof(stream1)){
                printf("%i\n", count/1024);
                unsigned short byte1=fgetwc(stream1);
                unsigned short byte2=fgetwc(stream2);
                count++;
                unsigned short buffer=((byte1+byte2)/2);
                fwprintf(stream3, L"%lc", buffer); }
        return 0; }    
Post 09 Feb 2007, 12:24
View user's profile Send private message Visit poster's website AIM Address Yahoo Messenger MSN Messenger Reply with quote
vid
Verbosity in development


Joined: 05 Sep 2003
Posts: 7105
Location: Slovakia
vid
kohlrak: list of functions in your code which can fail and must be checked:
- fopen
- fgetcw
- fwprintf
- even printf, but no one checks this one

and you are forgetting to close all 3 file handles, study "fclose" function.
Post 09 Feb 2007, 12:49
View user's profile Send private message Visit poster's website AIM Address MSN Messenger ICQ Number Reply with quote
LocoDelAssembly
Your code has a bug


Joined: 06 May 2005
Posts: 4633
Location: Argentina
LocoDelAssembly
Code:
unsigned short buffer=((byte1+byte2)/2);    


Shouldn't it be
Code:
unsigned short buffer=(((unsigned long)byte1+byte2)/2); 
    
?
Post 09 Feb 2007, 13:55
View user's profile Send private message Reply with quote
kohlrak



Joined: 21 Jul 2006
Posts: 1421
Location: Uncle Sam's Pad
kohlrak
Quote:
and you are forgetting to close all 3 file handles, study "fclose" function.


I know of it, but since it does nothing else in the program, it closes immediatly and dosn't hold anything up so it really woudln't make a difference if i used it or not.

LocoDelAssembly wrote:
Code:
unsigned short buffer=((byte1+byte2)/2);    


Shouldn't it be
Code:
unsigned short buffer=(((unsigned long)byte1+byte2)/2); 
    
?


Not really, as it should do the the DIV instruction immediatly after and use the EAX register which is 32bit. Just in case, i tried switching it around, anyway, but still got the same result. It might be the fact that they both had static to begin with, and that the added static had drastic (though this is probably a stretch from barely hearable static to blowing out your ears) effect.
Post 09 Feb 2007, 21:56
View user's profile Send private message Visit poster's website AIM Address Yahoo Messenger MSN Messenger Reply with quote
LocoDelAssembly
Your code has a bug


Joined: 06 May 2005
Posts: 4633
Location: Argentina
LocoDelAssembly
Quote:

Not really, as it should do the the DIV instruction immediatly after and use the EAX register which is 32bit.

It could use SHR too but I think that it should use AX in both cases since both operands in the addition are 16 bit. Have you dissasembled your program to verify this?
Post 09 Feb 2007, 22:03
View user's profile Send private message Reply with quote
f0dder



Joined: 19 Feb 2004
Posts: 3170
Location: Denmark
f0dder
kohlrak wrote:

I know of it, but since it does nothing else in the program, it closes immediatly and dosn't hold anything up so it really woudln't make a difference if i used it or not.

Just be glad that C/C++ stdlibs tend to fclose() all handles for you on program exit, otherwise you'd be screwed. Bad coding style.

kohlrak wrote:

Not really, as it should do the the DIV instruction immediatly after and use the EAX register which is 32bit. Just in case, i tried switching it around, anyway, but still got the same result. It might be the fact that they both had static to begin with, and that the added static had drastic (though this is probably a stretch from barely hearable static to blowing out your ears) effect.


WITH (unsigned long) typecast
Code:
movzx   eax, WORD PTR _byte2
movzx   ecx, WORD PTR _byte1
add             eax, ecx
shr             eax, 1
mov             WORD PTR _buffer, ax
    


WITHOUT typecast:
Code:
movzx   eax, WORD PTR _byte2
movzx   ecx, WORD PTR _byte1
add             eax, ecx
cdq
sub             eax, edx
sar             eax, 1
mov             WORD PTR _buffer, ax
    

In other words, do add the typecast, avoid overflows, be happy.
Post 10 Feb 2007, 00:33
View user's profile Send private message Visit poster's website Reply with quote
LocoDelAssembly
Your code has a bug


Joined: 06 May 2005
Posts: 4633
Location: Argentina
LocoDelAssembly
I thought that without the typecast the following code got used Confused
Code:
;unsigned short buffer=((byte1+byte2)/2);
mov ax, [byte1]
add ax, [byte2]
shr ax, 1
mov word [buffer], ax    
Post 10 Feb 2007, 01:42
View user's profile Send private message Reply with quote
f0dder



Joined: 19 Feb 2004
Posts: 3170
Location: Denmark
f0dder
LocoDelAssembly: depends on the compiler... VC prefers using 32bit ops, probably for speed reasons (it optimizes for the general case, compilers aren't wizards that know everything, they do follow relatively strict rules Smile ).
Post 10 Feb 2007, 01:50
View user's profile Send private message Visit poster's website Reply with quote
LocoDelAssembly
Your code has a bug


Joined: 06 May 2005
Posts: 4633
Location: Argentina
LocoDelAssembly
Quote:

depends on the compiler...

Quite bad, what if I intentionally want to loose bit 16 getting only the bits 15:0 of the addition? I thought that C language was very strict at this instead of auto promoting types just because it's faster. I'm a little disappointed knowing that it isn't true Sad

PS: Yes, I know I could use a mask to get only bits 15:0 but I'm introducing a new operation which could be avoided if just the compiler perform all the operations at the actual bigger operand type (unsigned short in the code without casting).
Post 10 Feb 2007, 02:54
View user's profile Send private message Reply with quote
f0dder



Joined: 19 Feb 2004
Posts: 3170
Location: Denmark
f0dder
If you look at the code, both versions only store 16 bits of the result... and the version without typecast has some cdq+sub+sar magic.
Post 10 Feb 2007, 03:08
View user's profile Send private message Visit poster's website Reply with quote
LocoDelAssembly
Your code has a bug


Joined: 06 May 2005
Posts: 4633
Location: Argentina
LocoDelAssembly
Code:
unsigned short var1 = 0x8000;
unsigned short var2 = 0x8000;
unsigned short var3=(var1+var2)/2;
    


With
Code:
;unsigned short var3=((var1+var2)/2); 
mov ax, [var1] 
add ax, [var2] 
shr ax, 1 
mov word [var3], ax    


var3 == 0 and with
Code:
  movzx eax, word [var1]
  movzx ecx, word [var2]
  add   eax, ecx
  cdq
  sub   eax, edx
  sar   eax, 1
  mov   [var3], ax    


var3 == 0x8000

[edit]
Quote:
some cdq+sub+sar magic.


I figured out where I saw that at last Razz

Agner Fog wrote:
Dividing a signed integer by 2N:
; Example 16.4. Divide signed integer by 2^N
cdq
and edx, (1 shl n) - 1 ; (Or: shr edx,32-n)
add eax, edx
sar eax, n


The AND part is not present on your code because AND/ADD in your code is intelligently replaced by a single SUB. The part I don't found intelligent is doing a signed division on unsigned operands though...[/edit]
Post 10 Feb 2007, 03:41
View user's profile Send private message Reply with quote
kohlrak



Joined: 21 Jul 2006
Posts: 1421
Location: Uncle Sam's Pad
kohlrak
Quote:
It could use SHR too but I think that it should use AX in both cases since both operands in the addition are 16 bit. Have you dissasembled your program to verify this?


To be honest, no, but it's an educated guess.

Quote:
Just be glad that C/C++ stdlibs tend to fclose() all handles for you on program exit, otherwise you'd be screwed. Bad coding style.


Normally i do, but from times that i forgot before, i learned that you really can't see much of a difference, and i was too lazy to add more code to the function. It's like those certain cases where you decide you want to put in a void just so you don't have to type in "return."

Quote:
movzx eax, WORD PTR _byte2
movzx ecx, WORD PTR _byte1
add eax, ecx
cdq
sub eax, edx
sar eax, 1
mov WORD PTR _buffer, ax


I'm surprised that it does the left shift for the division.
Post 11 Feb 2007, 02:18
View user's profile Send private message Visit poster's website AIM Address Yahoo Messenger MSN Messenger Reply with quote
LocoDelAssembly
Your code has a bug


Joined: 06 May 2005
Posts: 4633
Location: Argentina
LocoDelAssembly
Quote:

I'm surprised that it does the left shift for the division.

In fact right arithmetic shift (copies the sign bit on every shift). It's used for speed reasons and the CDQ/SUB part is for mimic the IDIV behavior (i.e. [-3 IDIV 2 = -1] but [-3 SAR 1 = -2]). But I'm still don't understand why those "auto type promotions" and why using signed division on unsigned types Confused
Post 11 Feb 2007, 03:42
View user's profile Send private message Reply with quote
Display posts from previous:
Post new topic Reply to topic

Jump to:  


< Last Thread | Next Thread >
Forum Rules:
You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot vote in polls in this forum
You can attach files in this forum
You can download files in this forum


Copyright © 1999-2020, Tomasz Grysztar.

Powered by rwasa.