How to convert 4 uint8_t array elements into float in Objective c?
I tried the shift operator and it doesn't seem to work:(
Are you thinking of something as undefined as this?:
union U8f {
uint8_t byte[4];
float f;
};
...
union U8f u8f;
u8f.byte[0] = ...
u8f.byte[1] = ...
...
float f = u8f.f;
Remember, byte order matters. I'll stand back and wait for the well deserved criticism. ;-)
The same way you do it in plain old C, cast it:
float f = (float) intArray[x];
Full example:
#import <Foundation/Foundation.h>
int
main(int argc, char** argv)
{
NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init];
uint8_t ints[4] = { 1, 2, 3, 4 };
float floats[4];
floats[0] = (float) ints[0];
floats[1] = (float) ints[1];
floats[2] = (float) ints[2];
floats[3] = (float) ints[3];
NSLog(#"floats[0]: %f", floats[0]);
NSLog(#"floats[1]: %f", floats[1]);
NSLog(#"floats[2]: %f", floats[2]);
NSLog(#"floats[3]: %f", floats[3]);
[pool release];
}
Related
(Update: found the answer, see below.)
I'm trying to play a 1 kHz sine wave tone in an Objective-C Cocoa app; I've (tried to) translate a Swift example to Objective-C, but there must be a mistake somewhere, as the resulting tone is around 440 Hz instead of 1 kHz, and only on the left channel.
The code:
#property (nonatomic, strong) AVAudioEngine *audioEngine;
#property (nonatomic, strong) AVAudioPlayerNode *player;
#property (nonatomic, strong) AVAudioMixerNode *mixer;
#property (nonatomic, strong) AVAudioPCMBuffer *buffer;
// -----
self.audioEngine = [[AVAudioEngine alloc] init];
self.player = [[AVAudioPlayerNode alloc] init];
self.mixer = self.audioEngine.mainMixerNode;
self.buffer = [[AVAudioPCMBuffer alloc] initWithPCMFormat:[self.player outputFormatForBus:0] frameCapacity:100];
self.buffer.frameLength = 100;
float amplitude = 0.4;
float frequency = 1000;
float sampleRate = [[self.mixer outputFormatForBus:0] sampleRate];
NSInteger channelCount = [[self.mixer outputFormatForBus:0] channelCount];
float *const *floatChannelData = self.buffer.floatChannelData;
float *p2 = *floatChannelData;
NSLog(#"Sine generator: sample rate = %.1f, %ld channels, frame length = %u.", sampleRate, (long)channelCount, self.buffer.frameLength);
for (int i = 0; i < self.buffer.frameLength ; i += channelCount) {
// a = Amplitude
// n = current sample
// r = Sample rate (samples / sec.)
//
// f(n) = a * sin( theta(n) )
// where theta(n) = 2 * M_PI * n / r
float theta = 441.0f * i * 2.0 * M_PI / sampleRate;
float value = sinf(theta);
p2[i] = value * amplitude;
}
[self.audioEngine attachNode:self.player];
[self.audioEngine connect:self.player to:self.mixer format:[self.player outputFormatForBus:0]];
[self.audioEngine startAndReturnError:nil];
[self.player play];
[self.player scheduleBuffer:self.buffer atTime:nil options:AVAudioPlayerNodeBufferLoops completionHandler:nil];
I suspect that there is either a math error in the float theta=... line, or I'm making a mistake with the floatChannelData buffer. The original Swift line reads:
buffer.floatChannelData.memory[i] = val * 0.5
Not sure what to make of the float *const * type of floatChannelData exactly. My understanding is that this is a pointer to 2 x float * const arrays. (2 because of the number of channels, left/right.)
The source of the Swift code is here: http://www.tmroyal.com/playing-sounds-in-swift-audioengine.html
It would be really nice if somebody could explain the buffer structure to me.
Found the solution
The problem was two-fold. First, the value 441.0 did indeed control the frequency. But changing that alone did not solve the problem; the resulting tone was more sawtooth-like than sine, and found out why.
With the factor 441 and a sample rate of 44.1 kHz, the ratio of those value was 1:100 - exactly the number of samples in the buffer. Changing 441 to a value that is not a whole multiple of that results in an "incomplete" sine wave: the value in the last sample frame (#100) is not zero, which causes a sharp drop-off when the loop starts again - and that sounds like a sawtooth wave.
I had to change the frame buffer length to be exactly (or a multiple of) the frequency-to-sample-rate ratio, so that the last sample value was (close to) zero.
The updated code:
self.audioEngine = [[AVAudioEngine alloc] init];
self.player = [[AVAudioPlayerNode alloc] init];
self.mixer = self.audioEngine.mainMixerNode;
float sampleRate = [[self.mixer outputFormatForBus:0] sampleRate];
AVAudioFrameCount frameBufferLength = floor(sampleRate / self.frequency) * 1;
self.buffer = [[AVAudioPCMBuffer alloc] initWithPCMFormat:[self.player outputFormatForBus:0] frameCapacity:frameBufferLength];
self.buffer.frameLength = frameBufferLength;
NSInteger channelCount = [[self.mixer outputFormatForBus:0] channelCount];
float *const *floatChannelData = self.buffer.floatChannelData;
NSLog(#"Sine generator: sample rate = %.1f, %ld channels, frame length = %u.", sampleRate, (long)channelCount, self.buffer.frameLength);
for (int i = 0; i < self.buffer.frameLength ; i ++) {
float theta = self.frequency * i * 2.0 * M_PI / sampleRate;
float value = sinf(theta);
for (int channelNumber = 0; channelNumber < channelCount ; channelNumber++) {
float * const channelBuffer = floatChannelData[channelNumber];
channelBuffer[i] = value * self.amplitude;
}
}
That way any number of channels are handled correctly, too.
The frequency part is easy: the literal 441.0f in your calculation of theta controls that, so just change it to whatever you want.
For the mono issue, you appear to only be writing one channel of data: p2[i] = value * amplitude; If you're correct about the composition of floatChannelData, then you want this:
float * const * floatChannelData = self.buffer.floatChannelData;
float * const left = floatChannelData[0];
float * const right = floatChannelData[1];
//...
// N.B. Changed the increment
for (int i = 0; i < self.buffer.frameLength ; i++ ) {
// ...
left[i] = value * amplitude;
right[i] = value * amplitude;
}
However, given the increment step in your for loop, it's possible that your buffer is interleaved (left and right channels alternating in the same buffer). In that case, you leave the loop increment, but write to both p2[i] and p2[i+1] on each step (easy for stereo; if you had more channels, you'd do an inner loop over those and write to p2[j] for j from 0 to $NUM_CHANNELS).
I have a student structure that provides the following code:
#import <Foundation/Foundation.h>
#import "Grades.m"
#import <stdio.h>
struct Student
{
NSString *myName;
struct Grades *myGrades;
};
void setName(struct Student *s, NSString *name);
void ssetGrades(struct Student *s, NSString *gradeList);
void setName(struct Student *s, NSString *name)
{
s->myName = name;
}
void ssetGrades(struct Student *s, NSString *gradeList)
{
printf("\n\nWorking\n\n");
setGrades(s->myGrades, gradeList);
printf("\n\nWorking");
}
I have a grades structure that provides the following:
#import <stdio.h>
#import <Foundation/Foundation.h>
#define null NULL
struct Grades
{
double sgrades[100];
int length;
};
void setGrades(struct Grades *grades, NSString *gradeList);
void setGrade(int spot, double grade, struct Grades *grades);
void setGrades(struct Grades *grades, NSString *gradeList)
{
NSString *a = [gradeList substringToIndex:1];
NSString *b = [gradeList substringWithRange:NSMakeRange(3, 19)];
int ln = [a integerValue];
grades->length = ln;
double grade;
int x = 1;
int prev = 1;
int y;
int z = 0;
for(y=0;y<ln;y++)
{
while(x < [b length] && [b characterAtIndex:x] != ' ')
{
z++;
x++;
}
NSString *sub = [b substringWithRange:NSMakeRange(prev, z)];
grade = [sub doubleValue];
printf("%d %d %d %lf\n", y, prev, z, grade);
prev += z+1;
x++;
z=0;
setGrade(y, grade, grades);
}
}
void setGrade(int spot, double grade, struct Grades *grades)
{
grades->sgrades[spot] = grade;
}
And finally, I have a main function with the following:
#import <Foundation/Foundation.h>
#import "Grades.m"
#import "Student.m"
#import <stdio.h>
int main (int argc, const char * argv[])
{
NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
struct Grades test;
setGrades(&test, #"5 - 90 85 95.5 77.5 88");
toString(&test);
printf("\nsum = %lf", getSum(&test));
printf("\nnum grades = %d", getNumGrades(&test));
printf("\nlow grade = %lf", getLowGrade(&test));
printf("\nhigh grade = %lf", getHighGrade(&test));
struct Student stu;
setName(&stu, #"Billy Bob");
ssetGrades(&stu, #"5 - 90 85 95.5 77.5 88");
[pool release];
return 0;
}
Now whenever I get to the ssetGrades (&stu, #"5 - 90 85 95.5 77.5 88") line in the main, it freezes up and says that the program has stopped working. Any guesses why and if so, how can I fix this error?
NOTE: This is all done in Notepad++ on Windows 7
Your primary issue is your definition of your Student structure. Change the Grades reference so it isn't a pointer:
struct Student
{
NSString *myName;
struct Grades myGrades;
};
The problem with the pointer is that you never initialize the pointer. By removing the pointer the memory issues causing the crash will go away.
As a result of this change, you need to change a few other things. The call to setGrades needs to pass the address of myGrades:
setGrades(&(s->myGrades), gradeList);
Even better would be to replace all of this struct/function code with actual classes.
"nan" and "nani" is being displayed in my output. I have discovered that this stands for "not a number", but I am not able to see where I am going wrong, and whether my problem lies with my lack of understanding of Objective-C, or imaginary numbers, or something else.
Any help or pointers would be much appreciated!
Thanks.
#import <Foundation/Foundation.h>
#interface Complex: NSNumber
-(void) setReal: (double) a;
-(void) setImaginary: (double) b;
-(void) print; // display as a + bi
-(double) real;
-(double) imaginary;
#end
#implementation Complex
{
double real;
double imaginary;
}
-(void) setReal: (double) a
{
real = a;
}
-(void) setImaginary: (double) b
{
imaginary = b;
}
-(void) print
{
NSLog (#"%f x %fi = %f", real, imaginary, real * imaginary);
}
-(double) real
{
return real;
}
-(double) imaginary
{
return imaginary;
}
#end
int main (int argc, const char * argv[])
{
#autoreleasepool {
Complex *complex1 = [[Complex alloc] init];
// Set real and imaginary values for first complex sum:
[complex1 setReal: 2];
[complex1 setImaginary: 3 * (sqrt(-1))];
// Display first complex number sum with print method:
NSLog (#"When a = 2 and b = 3, the following equation a x bi =");
[complex1 print];
//Display first complex number sum with getter method:
NSLog (#"When a = 2 and b = 3, the following equation
a x bi = %f x %fi = %fi", [complex1 real], [complex1 imaginary],
[complex1 real] * [complex1 imaginary]);
}
return 0;
}
Your NaNs come from sqrt(-1).
Do you want to implement your own complex types? C99 adds them, so unless you're using an ancient Objective-C compiler you'll be able to do something like this:
#include <complex.h>
double complex c = 3 * 2 I;
double r = creal(c);
double i = cimag(c);
There's some useful documentation and examples in the GNU libc manual: Complex Numbers.
The main problem is here:
[complex1 setImaginary: 3 * (sqrt(-1))];
The result of sqrt(-1) is NaN, sqrt() does not return "complex" numbers in any sense.
To set the imaginary part of your Complex object, you just set
[complex1 setImaginary: 3];
(setImaginary: expects a double argument, which makes sense because the imaginary part of a complex number is a real number.)
Remark: I have no idea what you want to achieve with your print method, but it does not
print a + bi as stated at the top of your program.
Exercise:
Write a program that converts 27° from degrees Fahrenheit (F) to degrees Celsius
(C) using the following formula:
C = (F - 32) / 1.8
Note that you don’t need to define a class to perform this calculation. Simply evaluating
the expression will suffice.
Here is my code:
#import <Foundation/Foundation.h>
int main (int argc, const char *argv[])
{
NSAutoreleasePool *pool=[[NSAutoreleasePool alloc] init];
float C;
float F;
F = 27;
C=(F-32)/1.8;
NSLog (#"27 degrees Fahrenheit is %f degrees Celsius." , C);
[drain pool];
return 0;
}
"Build failed"
On official forum there is a suggestion to write it this way :
#import <Foundation/Foundation.h>
int main (int argc, const char * argv[]) {
NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
double C, F;
F=27;
C=(F-32)/1.8;
int c=C;
NSLog(#"%g degrees Fahrenheit equals %i centigrades!", F, c);
[pool drain];
return 0;
}
But it also gives me "Failed" message.
What is not correct?
Update
Problem resolved.
I didn't set up initial settings of my project properly.
I was working inside other "C" programming language project.
I had to just create new project-> OS X -> Command line tool (type: Foundation) unmark "Use Automatic Reference Counting"
But the best part- i was rewarded with successfully compiled program:
2012-08-09 00:20:29.214 4.2[19452:403] 27 degrees Fahrenheit is -2.777778 degrees Celsius.
Thank you #trojanfoe , #john.k.doe , #drewk , #hol
This works:
#import <Foundation/Foundation.h>
int main(int argc, const char * argv[])
{
#autoreleasepool {
float C;
float F;
F = 27.0;
C=(F-32.0)/1.8;
NSLog (#"27 degrees Fahrenheit is %f degrees Celsius." , C);
}
return 0;
}
So does this:
#import <Foundation/Foundation.h>
int main (int argc, const char * argv[]) {
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
double F=27.2;
double C=(F-32.0)/1.8;
NSLog(#"%g degrees Fahrenheit equals %g centigrade!", F, C);
[pool drain];
return 0;
}
As you are not using objects even this will do it. Plain C.
int main(int argc, const char * argv[])
{
double C, F;
F=27;
C=(F-32)/1.8;
int c=C;
printf("%g degrees Fahrenheit equals %i centigrades!", F, c);
return 0;
}
Do you need to parse the arguments and calculate based on those?
How do I de-interleave the float *newAudio into float *channel1 and float* channel2 and interleave it back into newAudio?
Novocaine *audioManager = [Novocaine audioManager];
__block float *channel1;
__block float *channel2;
[audioManager setInputBlock:^(float *newAudio, UInt32 numSamples, UInt32 numChannels) {
// Audio comes in interleaved, so,
// if numChannels = 2, newAudio[0] is channel 1, newAudio[1] is channel 2, newAudio[2] is channel 1, etc.
// Deinterleave with vDSP_ctoz()/vDSP_ztoz(); and fill channel1 and channel2
// ... processing on channel1 & channel2
// Interleave channel1 and channel2 with vDSP_ctoz()/vDSP_ztoz(); to newAudio
}];
What would these two lines of code look like? I don't understand the syntax of ctoz/ztoz.
What I do in Novocaine's accessory classes, like the Ringbuffer, for de-interleaving:
float zero = 0.0;
vDSP_vsadd(data, numChannels, &zero, leftSampleData, 1, numFrames);
vDSP_vsadd(data+1, numChannels, &zero, rightSampleData, 1, numFrames);
for interleaving:
float zero = 0.0;
vDSP_vsadd(leftSampleData, 1, &zero, data, numChannels, numFrames);
vDSP_vsadd(rightSampleData, 1, &zero, data+1, numChannels, numFrames);
The more general way to do things is to have an array of arrays, like
int maxNumChannels = 2;
int maxNumFrames = 1024;
float **arrays = (float **)calloc(maxNumChannels, sizeof(float *));
for (int i=0; i < maxNumChannels; ++i) {
arrays[i] = (float *)calloc(maxNumFrames, sizeof(float));
}
[[Novocaine audioManager] setInputBlock:^(float *data, UInt32 numFrames, UInt32 numChannels) {
float zero = 0.0;
for (int iChannel = 0; iChannel < numChannels; ++iChannel) {
vDSP_vsadd(data, numChannels, &zero, arrays[iChannel], 1, numFrames);
}
}];
which is what I use internally a lot in the RingBuffer accessory classes for Novocaine. I timed the speed of vDSP_vsadd versus memcpy, and (very, very surprisingly), there's no speed difference.
Of course, you can always just use a ring buffer, and save yourself the hassle
#import "RingBuffer.h"
int maxNumFrames = 4096
int maxNumChannels = 2
RingBuffer *ringBuffer = new RingBuffer(maxNumFrames, maxNumChannels)
[[Novocaine audioManager] setInputBlock:^(float *data, UInt32 numFrames, UInt32 numChannels) {
ringBuffer->AddNewInterleavedFloatData(data, numFrames, numChannels);
}];
[[Novocaine audioManager] setOuputBlock:^(float *data, UInt32 numFrames, UInt32 numChannels) {
ringBuffer->FetchInterleavedData(data, numFrames, numChannels);
}];
Hope that helps.
Here is an example:
#include <Accelerate/Accelerate.h>
int main(int argc, const char * argv[])
{
// Bogus interleaved stereo data
float stereoInput [1024];
for(int i = 0; i < 1024; ++i)
stereoInput[i] = (float)i;
// Buffers to hold the deinterleaved data
float leftSampleData [1024 / 2];
float rightSampleData [1024 / 2];
DSPSplitComplex output = {
.realp = leftSampleData,
.imagp = rightSampleData
};
// Split the data. The left (even) samples will end up in leftSampleData, and the right (odd) will end up in rightSampleData
vDSP_ctoz((const DSPComplex *)stereoInput, 2, &output, 1, 1024 / 2);
// Print the result for verification
for(int i = 0; i < 512; ++i)
printf("%d: %f + %f\n", i, leftSampleData[i], rightSampleData[i]);
return 0;
}
sbooth answers how to de-interleave using vDSP_ctoz. Here's the complementary operation, namely interleaving using vDSP_ztoc.
#include <stdio.h>
#include <Accelerate/Accelerate.h>
int main(int argc, const char * argv[])
{
const int NUM_FRAMES = 16;
const int NUM_CHANNELS = 2;
// Buffers for left/right channels
float xL[NUM_FRAMES];
float xR[NUM_FRAMES];
// Initialize with some identifiable data
for (int i = 0; i < NUM_FRAMES; i++)
{
xL[i] = 2*i; // Even
xR[i] = 2*i+1; // Odd
}
// Buffer for interleaved data
float stereo[NUM_CHANNELS*NUM_FRAMES];
vDSP_vclr(stereo, 1, NUM_CHANNELS*NUM_FRAMES);
// Interleave - take separate left & right buffers, and combine into
// single buffer alternating left/right/left/right, etc.
DSPSplitComplex x = {xL, xR};
vDSP_ztoc(&x, 1, (DSPComplex*)stereo, 2, NUM_FRAMES);
// Print the result for verification. Should give output like
// i: L, R
// 0: 0.00, 1.00
// 1: 2.00, 3.00
// etc...
printf(" i: L, R\n");
for (int i = 0; i < NUM_FRAMES; i++)
{
printf("%2d: %5.2f, %5.2f\n", i, stereo[2*i], stereo[2*i+1]);
}
return 0;
}