challenge Tiny MML

文字列の入力をとり、音を鳴らすプログラムを作ってください。

入力はcがド、dがレ、eがミ、fがファ、gがソ、aがラ、bがシ、rが休符とします。この8文字以外の文字は入力に含まれていないと仮定して構いません。おのおのの音符・休符は八分音符・八分休符とします。

オクターブや音の長さの変更、同時発音などの機能は不要です。

サンプル入力(カエルの歌)

cdefedcrefgagfercrcrcrcrcdefedcr

Posted feedbacks - Objective-C

Mac OSX 10.4.10(Intel)で動作確認しています。Objective-CというよりAudio Unitの使い方ですね。
永野さんのページを参考にさせていただきました。
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
//コンパイルオプション:-std=gnu99 -fobjc-exceptions

#import <Foundation/Foundation.h>
#import <AppKit/AppKit.h>
#import <Audiounit/AudioUnit.h>

OSStatus callbackProc( void* inRefCon, AudioUnitRenderActionFlags* ioActionFlags,
		const AudioTimeStamp* inTimeStamp, UInt32 inBusNumber,
		UInt32 inNumberFrames, AudioBufferList* ioData ) {
	static const char notes[] = "cdefedcrefgagfercrcrcrcrcdefedcr";	//かえるの歌
	static const unsigned int length = sizeof notes - 1;	//音符の数
	static const float scale[] = { 440, 495, 264, 297, 330, 352, 396 };	//純正律音階
    static const float samplingRate = 44100;
	
	static unsigned int tempo = 160;	//テンポ:八分音符/分
	static unsigned int consumedFrames = 0;	//現在の音符の発音済みフレーム数。1分間だとsamplingRate*60
	static unsigned int index = 0;	//音符のインデックス
	static float phase = 0;
	
	char note = notes[index];
    float frequency = ( note >= 'a' && note <= 'g' ) ? scale[note - 'a'] : 0;
    frequency *= 2 * M_PI / samplingRate;

    float* outL = ioData->mBuffers[0].mData;
    float* outR = ioData->mBuffers[1].mData;

    for ( int i = 0; i < inNumberFrames; i++ ) {
        float wave = sin( phase );
        *outL++ = wave;
        *outR++ = wave;
        phase += frequency;
    }
	
	consumedFrames += inNumberFrames;
	//規定の時間が過ぎたら次の音符へ
	if ( consumedFrames >= samplingRate * 60 / tempo ) {
		consumedFrames = 0;
		//曲を最後まで演奏したら終了
		if ( ++index >= length )
			[NSApp terminate:nil];
	}
	
    return noErr;
}

BOOL initAudioUnit() {
	@try {
		ComponentDescription description = {
			kAudioUnitType_Output, kAudioUnitSubType_DefaultOutput, 
			kAudioUnitManufacturer_Apple, 0, 0
		};
		
		Component component = FindNextComponent( NULL, &description );
		if ( component == 0 )
			@throw @"Faild to find component.";
		
		AudioUnit audioUnit;
		if ( OpenAComponent( component, &audioUnit ) != noErr )
			@throw @"Faild to open component.";
		
		AURenderCallbackStruct callbackStruct = { callbackProc, NULL };
		if ( AudioUnitSetProperty( audioUnit, kAudioUnitProperty_SetRenderCallback,
				kAudioUnitScope_Input, 0, &callbackStruct, sizeof callbackStruct ) != noErr )
			@throw @"Faild to set property values for audio unit.";
		
		if ( AudioUnitInitialize( audioUnit ) != noErr )
			@throw @"Faild to initialize audio unit.";
		
		if ( AudioOutputUnitStart( audioUnit ) != noErr )
			@throw @"Faild to start audio unit.";
	} @catch ( id error ) {
		NSLog( error );
		return NO;
	}
	
	return YES;
}

int main( int argc, const char** argv ) {
    NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
	
	[NSApplication sharedApplication];
	if ( initAudioUnit() )
		[NSApp run];
	
    [pool release];
    return 0;
}

Index

Feed

Other

Link

Pathtraq

loading...