Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Features
Speaker Deck
PRO
Sign in
Sign up for free
Search
Search
シンセサイザー入門
Search
Fadis
May 09, 2015
Programming
0
580
シンセサイザー入門
mbedのDAコンバータを使って色んな方式のシンセサイザーの仕組みを解説します
Fadis
May 09, 2015
Tweet
Share
More Decks by Fadis
See All by Fadis
ゲームの物理 剛体編
fadis
0
470
ゲームの物理
fadis
5
2k
バイラテラルアップサンプリング
fadis
4
960
Kernel/VM探検隊@関西 11回目 大阪駅から会場までの道のりマップ
fadis
0
290
C++でシェーダを書く
fadis
6
5.2k
ライトたくさんReSTIRを実装しよう
fadis
3
1.6k
コンピュータグラフィクスの空
fadis
8
2.8k
NNEFを読めるようになろう
fadis
0
1.2k
低レイヤーから始める GUI
fadis
18
12k
Other Decks in Programming
See All in Programming
Apache Iceberg V3 and migration to V3
tomtanaka
0
160
Honoを使ったリモートMCPサーバでAIツールとの連携を加速させる!
tosuri13
1
180
15年続くIoTサービスのSREエンジニアが挑む分散トレーシング導入
melonps
2
220
AI巻き込み型コードレビューのススメ
nealle
2
420
CSC307 Lecture 05
javiergs
PRO
0
500
CSC307 Lecture 06
javiergs
PRO
0
690
AIエージェントのキホンから学ぶ「エージェンティックコーディング」実践入門
masahiro_nishimi
5
470
余白を設計しフロントエンド開発を 加速させる
tsukuha
7
2.1k
ぼくの開発環境2026
yuzneri
0
240
組織で育むオブザーバビリティ
ryota_hnk
0
180
Raku Raku Notion 20260128
hareyakayuruyaka
0
330
「ブロックテーマでは再現できない」は本当か?
inc2734
0
1k
Featured
See All Featured
WCS-LA-2024
lcolladotor
0
450
DBのスキルで生き残る技術 - AI時代におけるテーブル設計の勘所
soudai
PRO
62
50k
世界の人気アプリ100個を分析して見えたペイウォール設計の心得
akihiro_kokubo
PRO
66
37k
The B2B funnel & how to create a winning content strategy
katarinadahlin
PRO
1
280
State of Search Keynote: SEO is Dead Long Live SEO
ryanjones
0
120
Building the Perfect Custom Keyboard
takai
2
690
Crafting Experiences
bethany
1
49
Practical Orchestrator
shlominoach
191
11k
Why Our Code Smells
bkeepers
PRO
340
58k
AI: The stuff that nobody shows you
jnunemaker
PRO
2
260
Speed Design
sergeychernyshev
33
1.5k
How to train your dragon (web standard)
notwaldorf
97
6.5k
Transcript
γϯηαΠβʔೖ
দྛঘཧ !GBEJT@ 5XJUUFS ࣗݾհ
দྛঘཧ IUUQTHJUIVCDPN'BEJT HJUIVC͡Ί·ͨ͠ ࠓճհ͢Δίʔυ ͜͜Ͱެ։த ࣗݾհ
ݹͷੲ ୈҰճΧʔωϧ7.୳ݕୂ!ؔ CFFQԻͰԿ͕ग़དྷΔ͔
ࠓճΦʔσΟΦωλ CFFQԻͳΜͯένष͍͜ͱݴΘͣ ΨνͰγϯηαΠβʔΛ࡞Δ
ԻͷपʹΑͬͯԻ֊͕มΘΔ ͜͜ ͜͜
ؚ·Ε͍ͯΔपʹΑͬͯԻ৭͕มΘΔ ͜͜ͱ͔
γϯηαΠβʔͷجຊ ҙਤͨ͠Ի֊ʹରԠ͢ΔपΛ ओͱ͢ΔΛ࡞Δ
ྲྀߦͷϚΠίϯNCFE͞Μ AnalogOut
#include "mbed.h" AnalogOut audio_out(p18); const float freq_table[ 8 ] =
{ 523.25113f, 587.32953f, 659.25511f, 698.45646f, 783.99087f, 880.00000f, 987.76660f, 1046.5022f, }; int main() { while(1) { for( int note = 0; note != 8; ++note ) for( float time = 0.0f; time < 1.0f; time += 1.0f/16000.0f ) { Timer used_time; used_time.start(); audio_out = sinf( time * freq_table[ note ] * 3.141592f * 2.0f ) * 0.5f + 0.5f; used_time.stop(); wait(1.0f/16000.0f-used_time.read()); } } }
αΠζͷ߹ͰಈըΧοτʜ
ͬͱෳࡶͳԻΛग़͍ͨ͠ ϑΝϛίϯۣܗͱࡾ֯ͷ छྨͷܗ͔͑͠ͳ͍ͷʹ ଟ࠼ͳԻ৭ΛͰΔ͜ͱ͕ग़དྷΔͷԿނ͔ ۣܗ ࡾ֯
Τϯϕϩʔϓ ͬͱෳࡶͳԻΛग़͍ͨ͠ ԻྔΛܦա࣌ؒʹԠͯ͡มԽͤ͞Δ ͜͜Ͱ໐Β͢ͷΛΊͨ ͜͜Ͱ໐Β͠͡Ίͨ
ΞλοΫ ϐΞϊ όΠΦϦϯ ໐Γ͡Ίͷ Իྔ͕࠷େ͖͍ ໐Γ͡Ί͔ͯΒ ঃʑʹԻྔ͕େ͖͘ͳΔ ͜ͷ෦ͷ͞Λม͑Δ͜ͱͰରԠ
σΟέΠ γϩϑΥϯ Ϊλʔ ໐Β͠͡Ίͯ࠷େԻྔʹୡͨ͠ޙ ͙͢ʹԻྔ͕Լ͕Δ ໐Β͠͡Ίͯ࠷େԻྔʹୡͨ͠ޙ Ώͬ͘ΓԻྔ͕Լ͕Δ ͜ͷ෦ͷ͞Λม͑Δ͜ͱͰରԠ
αεςΠϯ ϐΞϊ ΦϧΨϯ ݤ൫Λԡ͍ͯ͠Δ࣌ؒʹؔΘΒͣ ͋Δఔͷ࣌ؒͰԻ͕ফ͑Δ ݤ൫Λԡ͍ͯ͠ΔݶΓࡍݶͳ͘ Ի͕໐Γଓ͚Δ ͜ͷ෦ͷେ͖͞Λม͑Δ͜ͱͰରԠ
ϦϦʔε ΦϧΨϯ ενʔϧυϥϜ ͘ͷΛΊΔͱ ൺֱత࣌ؒͰԻ͕ফ͑Δ ͜ͷ෦ͷ͖Λม͑Δ͜ͱͰରԠ ͘ͷΛΊͯԻ͕ ফ͑Δ·Ͱʹ͋Δఔͷ࣌ؒΛཁ͢
Τϯϕϩʔϓ º
#include "mbed.h" AnalogOut audio_out(p18); DigitalIn button(p19); class Envelope { bool
note_stat; float prev; public: Envelope() : note_stat( true ), prev( 0.0f ) {} void off() { note_stat = false; } float operator()( float _time ) { if( note_stat ) { if( _time < 0.2f ) prev = _time / 0.2f; else if( _time < 0.7f ) prev = 1.0f - ( _time - 0.2f ); else prev = 0.5f; return prev; } else return ( prev - _time < 0.0f ) ? 0.0f : prev - _time; } }; int main() { while(1) { Envelope envelope; float time, note_off_time; for( time = 0.0f; button; time += 1.0f/16000.0f ) { Timer used_time; used_time.start(); audio_out = envelope( time ) * sinf( time * 880.0f * 3.141592f * 2.0f ) * 0.4f + 0.5f; used_time.stop(); wait(1.0f/16000.0f-used_time.read()); } envelope.off(); for( note_off_time = time; !button; time += 1.0f/16000.0f ) { Timer used_time; used_time.start(); audio_out = envelope( time - note_off_time ) * sinf( time * 880.0f * 3.141592f * 2.0f ) * 0.4f + 0.5f; used_time.stop(); wait(1.0f/16000.0f-used_time.read()); } } }
αΠζͷ߹ͰಈըΧοτʜ
ϋϞϯυΦϧΨϯ αΠϯͱ͔ۣܗͱ͔Ͱͳ͘ ͬͱෳࡶͳܗΛ͏͜ͱͰ ଟ࠼ͳԻ৭ΛͰ͍ͨ ෳͷαΠϯΛॏͶ߹ΘͤΔ ࡞ઓ
ϋϞϯυΦϧΨϯ ഒ ഒ ഒ ഒ ̏ഒ ̐ഒ ഒ ̒ഒ ഒ
جԻ ͜ΕΒͷഒԻΛҙͷԻྔͰॏͶ߹ΘͤΔ
ϋϞϯυΦϧΨϯ ຊͷϋϞϯυΦϧΨϯ αΠϯͷࠁ·Εͨຕͷԁ൫Λ ߴճసͤ͞Δ͜ͱͰ֤पͷΛ࡞͍ͬͯͨ ϚΠίϯͰ؆୯ʹαΠϯΛ࡞ΕΔ࣌Ͱ ຊʹྑ͔ͬͨ
... template< typename Traits > class Hammond { public: Hammond(){}
fixed32< 16 > operator()( fixed32< 16 > _time ) { static const fixed32< 16 > scale_16 = 220.0f; static const fixed32< 16 > scale_8 = 440.0f; static const fixed32< 16 > scale_513 = 659.3f; static const fixed32< 16 > scale_4 = 880.0f; static const fixed32< 16 > scale_223 = 1318.5f; static const fixed32< 16 > scale_2 = 1760.0f; static const fixed32< 16 > scale_135 = 2217.0f; static const fixed32< 16 > scale_113 = 2637.0f; static const fixed32< 16 > scale_1 = 3520.0f; fixed32< 16 > sum = 0.0f; sum += sint( _time * scale_16 ) * Traits::level_16; sum += sint( _time * scale_8 ) * Traits::level_8; sum += sint( _time * scale_513 ) * Traits::level_513; sum += sint( _time * scale_4 ) * Traits::level_4; sum += sint( _time * scale_223 ) * Traits::level_223; sum += sint( _time * scale_2 ) * Traits::level_2; sum += sint( _time * scale_135 ) * Traits::level_135; sum += sint( _time * scale_113 ) * Traits::level_113; sum += sint( _time * scale_1) * Traits::level_1; fixed32< 16 > max = 0.0f; max += Traits::level_16; max += Traits::level_8; max += Traits::level_513; max += Traits::level_4; max += Traits::level_223; max += Traits::level_2; max += Traits::level_135; max += Traits::level_113; max += Traits::level_1; sum /= max; return sum; } private: }; ...
αΠζͷ߹ͰಈըΧοτʜ
ϋϞϯυΦϧΨϯ ϑʔϦΤڃΑΓ ͋ΒΏΔܗαΠϯͷॏͶ߹ΘͤͰ࡞ΕΔ͕ Ұൠʹेͳ࣭ΛಘΔҝʹཁٻ͞ΕΔ αΠϯͷඇৗʹଟ͘ ͔͔ͨͩݸఔͷαΠϯͰ େͨ͠Ի৭ͷࣗ༝ಘΒΕͳ͍
'.Իݯ αΠϯͱ͔ۣܗͱ͔Ͱͳ͘ ͬͱෳࡶͳܗΛ͏͜ͱͰ ଟ࠼ͳԻ৭ΛͰ͍ͨ '.มௐΛͬͯαΠϯΛΊΔ ࡞ઓ
ΦϖϨʔλ PVUQVUTJO DMPDL JOQVU FOWFMPQF ·ͨผͷΦϖϨʔλ ΦʔσΟΦग़ྗ·ͨผͷΦϖϨʔλ
ΦϖϨʔλྻͷ'.Իݯ ΦϖϨʔλ ΦϖϨʔλ ΦʔσΟΦग़ྗ
ΦϖϨʔλฒྻͷ'.Իݯ ΦϖϨʔλ ΦϖϨʔλ ΦʔσΟΦग़ྗ
ೖྗଆͷԻྔͰΈ۩߹͕ௐઅͰ͖Δ ΦϖϨʔλ ΦϖϨʔλ ΦϖϨʔλ ΦϖϨʔλ
ೖྗଆͷԻྔͰΈ۩߹͕ௐઅͰ͖Δ PVUQVUTJO DMPDL JOQVU FOWFMPQF ΦϖϨʔλʹ Τϯϕϩʔϓ͕͍͍ͭͯΔ ΦʔσΟΦग़ྗʹܨ͕͍ͬͯͳ͍ ΦϖϨʔλͷΤϯϕϩʔϓ
ܗͷΈΛ࣌ؒมԽͤ͞ΔͨΊʹ͑Δ
... class Const { public: fixed32< 16 > operator()( fixed32<
16 > _time ) { static const fixed32< 16 > value = 0; return value; } }; ! template< typename Source > class FM { public: FM() {} void off( fixed32< 16 > _off_time ) { envelope.off( _off_time ); } fixed32< 16 > operator()( fixed32< 16 > _time ) { fixed32< 16 > looped_time = _time - static_cast< int >( _time ); return sint( ( looped_time * 880.0f + source( _time ) / 2 ) ) * envelope( _time ); } private: Source source; Envelope envelope; }; ! int main() { while(1) { FM< FM< Const > > fm; fixed32< 16 > time, note_off_time; for( time = 0.0f; button; time += 1.0f/16000.0f ) { Timer used_time; used_time.start(); audio_out = fm( time ) * 0.4f + 0.5f; used_time.stop(); wait(1.0f/16000.0f-used_time.read()); } fm.off( time ); ...
αΠζͷ߹ͰಈըΧοτʜ
'.Իݯ '.มௐͷ݁Ռײతʹ༧͠ਏ͍ͨΊ ҙਤͨ͠Ի৭Λ࡞ΔͨΊʹࢼߦࡨޡ͕ඞཁ
ܗςʔϒϧԻݯ αΠϯͱ͔ۣܗͱ͔Ͱͳ͘ ͬͱෳࡶͳܗΛ͏͜ͱͰ ଟ࠼ͳԻ৭ΛͰ͍ͨ ࣄલʹ༻ҙͨ͠ܗσʔλΛ͏ ࡞ઓ
ܗςʔϒϧԻݯ ٕज़తʹ໘ന͘ͳ͍͚Ͳ ͦΕͳΓʹྑ͍Ի͕ग़Δํ๏ ͋Β͔͡Ίຊͷָث͔ΒԻ͖ͯͨ͠ ܗσʔλΛԻ֊ʹରԠ͢Δ͞ͰᢞΊΔ ྻ
... class Guiter { public: virtual fixed32< 16 > operator()(
fixed32< 16 > _pos ) { static const int16_t guiter_table[ 512 ] = { -32735, -32583, -32431, -32279, -32127, -31975, -31823, -31671, ... -27519, -28171, -28823, -29475, -30127, -30779, -31431, -32083, }; fixed32< 16 > result; fixed32< 16 > a4 = _pos * 220.0f; int pos = ( a4.get() >> 7 ) % 512; // pos = pos * 880 % 512; int32_t value = static_cast< int32_t >( guiter_table[ pos ] ) << 1; result.set( value ); return result * envelope( _pos ); } void off( fixed32< 16 > _off_time ) { envelope.off( _off_time ); } private: Envelope envelope; }; ...
αΠζͷ߹ͰಈըΧοτʜ
ܗςʔϒϧԻݯ ࣮ͷଘࡏ͠ͳ͍ԻΛ࡞Δͷࠔ ࣌ؒมԽ͢ΔԻ৭Λѻ͏ͷ͕ࠔ
࠷ऴతʹग़དྷ্͕ͬͨͷ ͦͷଞ৭ʑ࣮͚ͨ͠Ͳ ͦͷΜͷղઆ·ͨͷػձʹ Ψοπͷ͋Δਓ ιʔεΛݟͯΈΔͱ͍͍͔
IUUQZPVUVCFSY5RX&:#.
ษڧձ෮शࢿྉ IUUQCJUMZF2,WE& ιʔείʔυ IUUQCJUMZRJBR'
͝ਗ਼ௌ͋Γ͕ͱ͏͍͟͝·ͨ͠