EDIT after Ben's answer
I'm trying to do something that should be very easy for someone who uses signal processing, but it gives me headaches. I'm just trying to create a wave sound that will play an arbitrary number of seconds, maybe less or more than a second (0.1s, 0.88s, 1.2s, ...).
To create a wave sound, I use this famous method:
+ (NSData*) WAVSoundForFrequency:(float)frequency duration:(float)seconds sampleRate:(unsigned int)sampleRate gain:(float)gain { int frames = seconds * sampleRate; float* rawSound = (float*)malloc(frames*sizeof(float)); if (rawSound == NULL) return nil; for (int i = 0; i < frames; i++) rawSound[i] = gain * sinf(i*2*M_PI*frequency/sampleRate);
This is called basic with:
AVAudioPlayer* player = [self.audioPlayerManager buildSoundFrequency:200 duration:0.18 sampleRate:44100 gain:1.0]; player.volume = 1.0; player.numberOfLoops = -1; [player play];
The problem is that with these parameters, the wave does not seem complete at the end, so it generates clicks that can be heard in each cycle. But without a click, if I use 0.5 seconds or 1.0 seconds for a duration of 200 hertz (using an adjusted course, of course). Still for testing purposes, if I use 400 hertz or 440 hertz instead of 200, I now have clicks from 0.5 s.
Please note that the cycle exists only for testing and searching if there are clicks or not. At the end, the sound should be reproduced only at the desired duration.
I guessed that this was due to the duration, which is not round, a multiple of the wave cycle, so I set up such a call to set the desired duration to the nearest duration, which would be a multiple of one cycle at the required frequency:
float wantedDuration = 0.18; float hertz = 200; int wantedSampleRate = 44100; // Adjusting wanted duration so the duration contains an entiere number of waves float oneWaveDurationInSeconds = 1.0/hertz; int nbWavesNeeded = roundf(wantedDuration/oneWaveDurationInSeconds); float adjustedDuration = nbWavesNeeded * oneWaveDurationInSeconds; // Adjusting sample rate so one wave takes an entiere number of samples float oneSampleDuration = 1.0/wantedSampleRate; int adjustedSamplerate = wantedSampleRate; while (YES) { oneSampleDuration = 1.0/adjustedSamplerate; if (roundf(oneWaveDurationInSeconds/oneSampleDuration) == oneWaveDurationInSeconds/oneSampleDuration) break; adjustedSamplerate++; NSLog(@"%d", adjustedSamplerate); } // Debug float nbSamplesForOneWave = oneWaveDurationInSeconds / (1.0/adjustedSamplerate); NSLog(@"nbSamplesForOneWave : %f", nbSamplesForOneWave); // Execute MyAudioPlayer* player = [self.manager preloadSoundFrequency:hertz duration:adjustedDuration sampleRate:adjustedSamplerate gain:1.0 identifier:@"ii" category:@"Radar"]; player.volume = 1.0; player.numberOfLoops = -1; [player play];
But there is still a click.
I was told that the problem could be the sampling rate. But I really don't understand why. As I understand it, the sampling frequency is the number of samples determined in one second. So for me it does not depend on the duration or frequency.
And ... Why shouldn't I have 0.18 sound with 44100 sample quality ...
But in any case ... I thought that if I try 44100 points in one second, asking for a duration of 0.18 should lead to samples 44100 * 0.18. This number is represented by int frames
. So I tried to replace
rawSound[i] = gain * sinf(i*2*M_PI*frequency/sampleRate);
with
rawSound[i] = gain * sinf(i*2*M_PI*frequency/frames);
It does not work, it just makes the sound much sharper. And I still don’t understand why. I would say that it will be a less high-quality sound, since tere is just fewer samples.
Can someone help me create this (possibly encoded) wave sound for any desired delay, at the desired quality and frequency?
I'm sure the sounds (:-)) are easy, but I see no way to follow this goal.
I tried putting NSLog to see the values used (log without Paul ramps):
if (i<20 || i > frames-20) NSLog(@"%f", rawSound[i]);
For 440 Hz, sampling frequency 44100, duration 1.0 (no adjustment): No click
2011-10-31 01:02:34.110 testAudio[9602:207] 0.000000 2011-10-31 01:02:34.112 testAudio[9602:207] 0.062648 2011-10-31 01:02:34.113 testAudio[9602:207] 0.125051 2011-10-31 01:02:34.114 testAudio[9602:207] 0.186961 2011-10-31 01:02:34.115 testAudio[9602:207] 0.248138 2011-10-31 01:02:34.116 testAudio[9602:207] 0.308339 2011-10-31 01:02:34.116 testAudio[9602:207] 0.367330 2011-10-31 01:02:34.117 testAudio[9602:207] 0.424877 2011-10-31 01:02:34.117 testAudio[9602:207] 0.480755 2011-10-31 01:02:34.118 testAudio[9602:207] 0.534744 2011-10-31 01:02:34.119 testAudio[9602:207] 0.586632 2011-10-31 01:02:34.121 testAudio[9602:207] 0.636216 2011-10-31 01:02:34.121 testAudio[9602:207] 0.683300 2011-10-31 01:02:34.122 testAudio[9602:207] 0.727699 2011-10-31 01:02:34.123 testAudio[9602:207] 0.769240 2011-10-31 01:02:34.123 testAudio[9602:207] 0.807759 2011-10-31 01:02:34.124 testAudio[9602:207] 0.843104 2011-10-31 01:02:34.125 testAudio[9602:207] 0.875137 2011-10-31 01:02:34.126 testAudio[9602:207] 0.903732 2011-10-31 01:02:34.127 testAudio[9602:207] 0.928777 2011-10-31 01:02:34.130 testAudio[9602:207] -0.928790 2011-10-31 01:02:34.130 testAudio[9602:207] -0.903724 2011-10-31 01:02:34.131 testAudio[9602:207] -0.875102 2011-10-31 01:02:34.132 testAudio[9602:207] -0.843167 2011-10-31 01:02:34.132 testAudio[9602:207] -0.807795 2011-10-31 01:02:34.133 testAudio[9602:207] -0.769245 2011-10-31 01:02:34.134 testAudio[9602:207] -0.727667 2011-10-31 01:02:34.135 testAudio[9602:207] -0.683225 2011-10-31 01:02:34.135 testAudio[9602:207] -0.636283 2011-10-31 01:02:34.136 testAudio[9602:207] -0.586658 2011-10-31 01:02:34.137 testAudio[9602:207] -0.534724 2011-10-31 01:02:34.138 testAudio[9602:207] -0.480687 2011-10-31 01:02:34.138 testAudio[9602:207] -0.424978 2011-10-31 01:02:34.139 testAudio[9602:207] -0.367383 2011-10-31 01:02:34.140 testAudio[9602:207] -0.308342 2011-10-31 01:02:34.140 testAudio[9602:207] -0.248087 2011-10-31 01:02:34.141 testAudio[9602:207] -0.186856 2011-10-31 01:02:34.142 testAudio[9602:207] -0.125132 2011-10-31 01:02:34.142 testAudio[9602:207] -0.062676
For 440 Hz, sampling frequency 44100, duration 0.5 (without adjustment): No click
2011-10-31 01:04:51.043 testAudio[9714:207] 0.000000 2011-10-31 01:04:51.045 testAudio[9714:207] 0.062648 2011-10-31 01:04:51.047 testAudio[9714:207] 0.125051 2011-10-31 01:04:51.049 testAudio[9714:207] 0.186961 2011-10-31 01:04:51.049 testAudio[9714:207] 0.248138 2011-10-31 01:04:51.050 testAudio[9714:207] 0.308339 2011-10-31 01:04:51.051 testAudio[9714:207] 0.367330 2011-10-31 01:04:51.052 testAudio[9714:207] 0.424877 2011-10-31 01:04:51.053 testAudio[9714:207] 0.480755 2011-10-31 01:04:51.054 testAudio[9714:207] 0.534744 2011-10-31 01:04:51.055 testAudio[9714:207] 0.586632 2011-10-31 01:04:51.055 testAudio[9714:207] 0.636216 2011-10-31 01:04:51.056 testAudio[9714:207] 0.683300 2011-10-31 01:04:51.057 testAudio[9714:207] 0.727699 2011-10-31 01:04:51.059 testAudio[9714:207] 0.769240 2011-10-31 01:04:51.060 testAudio[9714:207] 0.807759 2011-10-31 01:04:51.060 testAudio[9714:207] 0.843104 2011-10-31 01:04:51.061 testAudio[9714:207] 0.875137 2011-10-31 01:04:51.062 testAudio[9714:207] 0.903732 2011-10-31 01:04:51.062 testAudio[9714:207] 0.928777 2011-10-31 01:04:51.064 testAudio[9714:207] -0.928795 2011-10-31 01:04:51.065 testAudio[9714:207] -0.903730 2011-10-31 01:04:51.065 testAudio[9714:207] -0.875109 2011-10-31 01:04:51.066 testAudio[9714:207] -0.843109 2011-10-31 01:04:51.067 testAudio[9714:207] -0.807731 2011-10-31 01:04:51.067 testAudio[9714:207] -0.769253 2011-10-31 01:04:51.068 testAudio[9714:207] -0.727676 2011-10-31 01:04:51.069 testAudio[9714:207] -0.683324 2011-10-31 01:04:51.070 testAudio[9714:207] -0.636199 2011-10-31 01:04:51.070 testAudio[9714:207] -0.586669 2011-10-31 01:04:51.071 testAudio[9714:207] -0.534736 2011-10-31 01:04:51.072 testAudio[9714:207] -0.480806 2011-10-31 01:04:51.072 testAudio[9714:207] -0.424880 2011-10-31 01:04:51.073 testAudio[9714:207] -0.367282 2011-10-31 01:04:51.074 testAudio[9714:207] -0.308355 2011-10-31 01:04:51.074 testAudio[9714:207] -0.248100 2011-10-31 01:04:51.075 testAudio[9714:207] -0.186989 2011-10-31 01:04:51.076 testAudio[9714:207] -0.125025 2011-10-31 01:04:51.077 testAudio[9714:207] -0.062689
For 440 Hz, sampling frequency 44100, duration 0.25 (no adjustment): Hard clicks
2011-10-31 01:05:25.245 testAudio[9759:207] 0.000000 2011-10-31 01:05:25.247 testAudio[9759:207] 0.062648 2011-10-31 01:05:25.249 testAudio[9759:207] 0.125051 2011-10-31 01:05:25.250 testAudio[9759:207] 0.186961 2011-10-31 01:05:25.251 testAudio[9759:207] 0.248138 2011-10-31 01:05:25.252 testAudio[9759:207] 0.308339 2011-10-31 01:05:25.252 testAudio[9759:207] 0.367330 2011-10-31 01:05:25.253 testAudio[9759:207] 0.424877 2011-10-31 01:05:25.254 testAudio[9759:207] 0.480755 2011-10-31 01:05:25.254 testAudio[9759:207] 0.534744 2011-10-31 01:05:25.255 testAudio[9759:207] 0.586632 2011-10-31 01:05:25.256 testAudio[9759:207] 0.636216 2011-10-31 01:05:25.257 testAudio[9759:207] 0.683300 2011-10-31 01:05:25.257 testAudio[9759:207] 0.727699 2011-10-31 01:05:25.258 testAudio[9759:207] 0.769240 2011-10-31 01:05:25.259 testAudio[9759:207] 0.807759 2011-10-31 01:05:25.260 testAudio[9759:207] 0.843104 2011-10-31 01:05:25.261 testAudio[9759:207] 0.875137 2011-10-31 01:05:25.261 testAudio[9759:207] 0.903732 2011-10-31 01:05:25.262 testAudio[9759:207] 0.928777 2011-10-31 01:05:25.263 testAudio[9759:207] -0.928781 2011-10-31 01:05:25.264 testAudio[9759:207] -0.903727 2011-10-31 01:05:25.264 testAudio[9759:207] -0.875135 2011-10-31 01:05:25.265 testAudio[9759:207] -0.843105 2011-10-31 01:05:25.266 testAudio[9759:207] -0.807763 2011-10-31 01:05:25.267 testAudio[9759:207] -0.769249 2011-10-31 01:05:25.267 testAudio[9759:207] -0.727692 2011-10-31 01:05:25.268 testAudio[9759:207] -0.683296 2011-10-31 01:05:25.269 testAudio[9759:207] -0.636217 2011-10-31 01:05:25.269 testAudio[9759:207] -0.586638 2011-10-31 01:05:25.270 testAudio[9759:207] -0.534756 2011-10-31 01:05:25.271 testAudio[9759:207] -0.480746 2011-10-31 01:05:25.271 testAudio[9759:207] -0.424873 2011-10-31 01:05:25.272 testAudio[9759:207] -0.367332 2011-10-31 01:05:25.273 testAudio[9759:207] -0.308348 2011-10-31 01:05:25.273 testAudio[9759:207] -0.248152 2011-10-31 01:05:25.274 testAudio[9759:207] -0.186952 2011-10-31 01:05:25.275 testAudio[9759:207] -0.125047 2011-10-31 01:05:25.276 testAudio[9759:207] -0.062652
EDIT
I launched the created sound sample (440 Hz, 444100 samples, 0.1 seconds) into a file and opened it using the sound editor. Cut and paste sound many times to make a longer sound: it plays without a click. The same sample of sound that is played through AVAudioPlayer generates clicks at the end of each sample. So the problem seems to be in AVAudioPlayer, for some reason I don’t understand, because only some specific values generate these clicks.
EDIT
I used the created wav file and ran it from AVAudioPlayer using a loop: clicks
I used the same file and ran it in a loop with OpenAL using a special library: no more clicks. The problem is that OpenAL is really a nightmare to understand and would lead to a remake of my audio part, just for that bad sound.
The problem seems to be using AVAudioPlayer. If you have a solution to make it work, it will save me a few days.