I am working on a project using DirectSound and am trying to make it so that the header information for the sound file is passed to the processing method. WAV files have a RIFF chunkID at the start. In a call to the ProcessWaveFile method, I pass the filepath as well as the header information. The 'RIFF' chunkID is stored in a char. I need to be able to check individual characters of the chunkID against the actual file chunkID to ensure the file is correct. This is a snippet of my code:
if((waveFileHeader.chunkId[0] != chunkID[0]) || (waveFileHeader.chunkId[1] != chunkID[1]) ||
(waveFileHeader.chunkId[2] != chunkID[2]) || (waveFileHeader.chunkId[3] != chunkID[3]))
{
MessageBox(hwnd, L"ChunkID not in the right Format.", L"Error", MB_OK);
return false;
}
chunkId is the file's actual ID whereas chunkID is the ID passed through the function to check. As you can see I'm trying to handle it like an array here. The chunkId is stored in a char[]. Should I store the chunkID in an array too? How would I specify it?
bool ProcessWaveFile(char*, IDirectSoundBuffer8**, HWND, int, char, char, char, char, std::string, int, int);
Above is the header file line for the ProcessWaveFile method. The chunkID is specified as one of the chars. I could change it to char[] but the difficulty comes when actually calling the method. Here is an example call:
result1 = ProcessWaveFile("../terrain_sky/data/sound01.wav", &m_secondaryBuffer1, hwnd,
44100, 'RIFF', 'fmt ', 'WAVE', 'data', "WAVE_PCM_FORMAT", 16, 2);
How could I declare the array values containg RIFF in this call without disrupting the chain of variables?
If you are looking for a convenient way to check that the file starts with 'RIFF', there may be a more convenient way for you to find out. Since the ChunkID is 4 bytes long, you may want to store what you expect 'RIFF' in a datatype that is also 4 bytes long (instead of a char array of length 4), then parse the first four bytes as, for example, an int.
I have a wav file that starts with RIFF here, here's what number you get when you interpret the first four bytes as an int.
od -ci -N4 ./test.wav
0000000 R I F F
1179011410
So the option -ci first prints each byte as its ASCII equivalent (RIFF), and then prints each set of 4 bytes as an integer. So really, 1179011410 = 'RIFF' and the integer may be easier for you to check for.
But as an aside, I'm not really sure why you need to pass 'RIFF' into the ProcessWaveFile() function. If you only ever deal with RIFF files, you might get away with having that information stored in the ProcessWaveFile() function itself.
Related
I'm trying to to read from a TXT file and do some calculation and write it back to another TXT file but when I read the character it changes to ASCII number (ex : '1' convert to 50) and when I try to write it in another file it's the ASCII number. How can I change it to that character I want?
int wf=FileOpen("wf.txt",FILE_WRITE|FILE_ANSI|FILE_TXT);
int rf=FileOpen("rf.txt",FILE_READ|FILE_ANSI|FILE_TXT);
str_size=FileReadInteger(rf,INT_VALUE); //the TXT I read is 1234
str=FileReadString(rf,str_size);
StringToCharArray(str,data1,0,StringLen(str));
RandonNum[0]= str[1];
RandonNum[1]= str[2];
RandonNum[2]= str[3];
FileWrite(wf,str[1],str[2],str[3]); //the TXT I write is 505152
FileReadInteger() is reserved for binary type files.
Unfortunately this is not explicitly stated in the documentation.
Use FileReadNumber() to read a number from txt file. It will return the number as a double, but it can be cast to an integer using a type cast (int)double_value.
In this project the user can type in a text(maximum 140 characters).
so for this limitation I once used getline():
string text;
getline(cin, text);
text = text.substr(1, 140);
but in this case the result of cout << text << endl; is an empty string.
so I used cin.get() like:
cin.get(text, 140);
this time I get this error: no matching function for call to ‘std::basic_istream::get(std::__cxx11::string&, int)’
note that I have included <iostream>
so the question is how can I fix this why is this happening?
Your first approach is sound with one correction - you need to use
text = text.substr(0, 140);
instead of text = text.substr(1, 140);. Containers (which includes a string) in C/C++ start with index 0 and you are requesting the string to be trimmed from position 1. This is perfectly fine, but if the string happens to be only one character long, calling text.substr(1, 140); will not necessarily cause the program to crash, but will not end up in the desired output either.
According to this source, substr will throw an out of range exception if called with starting position larger than string length. In case of a one character string, position 1 would be equal to string length, but the return value is not meaningful (in fact, it may even be an undefined behavior but I cannot find a confirmation of this statement - in yours and my case, calling it returns an empty string). I recommend you test it yourself in the interactive coding section following the link above.
Your second approach tried to pass a string to a function that expected C-style character arrays. Again, more can be found here. Like the error said, the compiler couldn't find a matching function because the argument was a string and not the char array. Some functions will perform a conversion of string to char, but this is not the case here. You could convert the string to char array yourself, as for instance described in this post, but the first approach is much more in line with C++ practices.
Last note - currently you're only reading a single line of input, I assume you will want to change that.
From the docs, unpack does:
Decodes str (which may contain binary data) according to the format
string, returning an array of each value extracted.
And the "C" format means 8-bit unsigned (unsigned char).
But what does this actually end up doing to the string I input? What does the result mean, and if I had to do it by hand, how would I go about doing that?
It converts each subsequent char to it’s integer ordinal as String#ord does. That said,
string.unpack 'C*'
is an exact equivalent of
string.each_char.map(&:ord)
But what does this actually end up doing to the string I input
It doesn't do anything to the input. And the input is not really a string here. It's typed as a string, but it is really a buffer of binary data, such as you might receive by networking, and your goal is to extract that data into an array of integers. Example:
s = "\01\00\02\03"
arr = s.unpack("C*")
p(arr) # [1,0,2,3]
That "string" would be meaningless as a string of text, but it is quite viable as a data buffer. Unpacking it allows you examine the data.
using visualworks, in small talk, I'm receiving a string like '31323334' from a network connection.
I need a string that reads '1234' so I need a way of extracting two characters at a time, converting them to what they represent in ascii, and then building a string of them...
Is there a way to do so?
EDIT(7/24): for some reason many of you are assuming I will only be working with numbers and could just truncate 3s or read every other char. This is not the case, examples of strings read could include any keys on the US standard keyboard (a-z, A-Z,0-9,punctuation/annotation such as {}*&^%$...)
Following along the lines of what Max started to suggest:
x := '31323334'.
in := ReadStream on: x.
out := WriteStream on: String new.
[ in atEnd ] whileFalse: [ out nextPut: (in next digitValue * 16 + (in next digitValue)) asCharacter ].
newX := out contents.
newX will have the result '1234'. Or, if you start with:
x := '454647'
You will get a result of 'EFG'.
Note that digitValue might only recognize upper case hex digits, so an asUppercase may be needed on the string before processing.
There is usually a #fold: or #reduce: method that will let you do that. In Pharo there's also a message #allPairsDo: and #groupsOf:atATimeCollect:. Using one of these methods you could do:
| collectionOfBytes |
collectionOfBytes := '9798'
groupsOf: 2
atATimeCollect: [ :group |
(group first digitValue * 10) + (group second digitValue) ].
collectionOfBytes asByteArray asString "--> 'ab'"
The #digitValue message in Pharo simply returns the value of the digit for numerical characters.
If you're receiving the data on a stream you could replace #groupsOf:atATime: with a loop (result may be any collection that you then convert to a string like above):
...
[ stream atEnd ] whileFalse: [
result add: (stream next digitValue * 10) + (stream next digitValue) ]
...
in Smalltalk/X, there is a method called "fromHexBytes:" which the ByteArray class understands. I am not sure, but think that something similar exists in other ST dialects.
If present, you can solve this with:
(ByteArray fromHexString:'68656C6C6F31323334') asString
and the reverse would be:
'hello1234' asByteArray hexPrintString
Another possible solution is to read the string as a hex number,
fetch the digitBytes (which should give you a byte array) and then convert that to a string.
I.e.
(Integer readFrom:'68656C6C6F31323334' radix:16)
digitBytes asString
One problem with that is that I am not sure about which byte-order you will get the digitBytes (LSB or MSB), and if that is defined to be the same across architectures or converted at image loading time to use the native order. So it may be required to reverse the string at the end (to be portable, it may even be required to reverse it conditionally, depending on the endianess of the system.
I cannot test this on VisualWorks, but I assume it should work fine there, too.
how can I split this barcode by group separator with Progress? I've tried chr(29) without any luck.
Barcode scanned into Notepad++: http://i.imgur.com/8DmPZ.png
Barcode scanned into input field: 2409271405202120330017100282
Thanks.
def var c as char no-undo.
def var i as int no-undo.
update c format "x(50)".
do i = 1 to length(c):
message substr(c, i, 1) = chr(29).
end.
The problem is that GS is an undefined control code. So you need to make it be recognized.
Add the following to your terminal's entry in protermcap to define GS as F13:
:(F13)=\035:\
(The octal code for GS is \035 and F13 is an undefined function key -- so the combination should work. I don't have a scanner to test with but this works for the control codes that I can type into my keyboard...)
Then use code like this:
define variable bc as character no-undo format "X(50)".
update bc editing:
if lastkey = 313 then
apply ".". /* 313 is the code for F13 */
else
apply lastkey.
end.
This should cause "." to be inserted instead of GS. Which will allow you to parse the string using "." rather than GS.
It's a wild guess, but I'm thinking ENTRY(entry-num, barcode-string, "group-separator-string")?
This works for me:
/* create a test file (otherwise not needed...)
*/
output to "barcode.dat".
put control "240927140520" chr(29) "2120330017" chr(29) "100282".
output close.
/* if you already have barcode.dat start here
*/
define variable m as memptr no-undo.
define variable bc as character no-undo.
set-size( m ) = 100.
input from "barcode.dat" binary no-convert.
import unformatted m.
input close.
bc = get-string( m, 1 ).
display
entry( 1, bc, chr(29)) format "x(12)" skip
entry( 2, bc, chr(29)) format "x(12)" skip
entry( 3, bc, chr(29)) format "x(12)" skip
.