Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 14 additions & 8 deletions study.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,8 @@
);
mainGroup = 2415A43F2DD0DF8E00EDC236;
minimizedProjectReferenceProxies = 1;
packageReferences = (
);
preferredProjectObjectVersion = 77;
productRefGroup = 2415A4492DD0DF8E00EDC236 /* Products */;
projectDirPath = "";
Expand Down Expand Up @@ -248,10 +250,11 @@
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 1;
DEVELOPMENT_ASSET_PATHS = "\"study/assets\"";
DEVELOPMENT_TEAM = WL6LTCP7D2;
DEVELOPMENT_TEAM = P26KYG6RH6;
ENABLE_HARDENED_RUNTIME = YES;
ENABLE_PREVIEWS = YES;
GENERATE_INFOPLIST_FILE = YES;
INFOPLIST_KEY_NSMicrophoneUsageDescription = "기타 소리를 듣고 피드백을 드리기 위해 마이크 접근 권한이 필요합니다.";
"INFOPLIST_KEY_UIApplicationSceneManifest_Generation[sdk=iphoneos*]" = YES;
"INFOPLIST_KEY_UIApplicationSceneManifest_Generation[sdk=iphonesimulator*]" = YES;
"INFOPLIST_KEY_UIApplicationSupportsIndirectInputEvents[sdk=iphoneos*]" = YES;
Expand All @@ -269,11 +272,12 @@
MARKETING_VERSION = 1.0;
PRODUCT_BUNDLE_IDENTIFIER = "ada-4th-c3.study";
PRODUCT_NAME = "$(TARGET_NAME)";
SDKROOT = auto;
SUPPORTED_PLATFORMS = "iphoneos iphonesimulator macosx xros xrsimulator";
SDKROOT = iphoneos;
SUPPORTED_PLATFORMS = "iphoneos iphonesimulator";
SUPPORTS_MACCATALYST = NO;
SWIFT_EMIT_LOC_STRINGS = YES;
SWIFT_VERSION = 5.0;
TARGETED_DEVICE_FAMILY = "1,2,7";
TARGETED_DEVICE_FAMILY = "1,2";
XROS_DEPLOYMENT_TARGET = 2.2;
};
name = Debug;
Expand All @@ -287,10 +291,11 @@
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 1;
DEVELOPMENT_ASSET_PATHS = "\"study/assets\"";
DEVELOPMENT_TEAM = WL6LTCP7D2;
DEVELOPMENT_TEAM = P26KYG6RH6;
ENABLE_HARDENED_RUNTIME = YES;
ENABLE_PREVIEWS = YES;
GENERATE_INFOPLIST_FILE = YES;
INFOPLIST_KEY_NSMicrophoneUsageDescription = "기타 소리를 듣고 피드백을 드리기 위해 마이크 접근 권한이 필요합니다.";
"INFOPLIST_KEY_UIApplicationSceneManifest_Generation[sdk=iphoneos*]" = YES;
"INFOPLIST_KEY_UIApplicationSceneManifest_Generation[sdk=iphonesimulator*]" = YES;
"INFOPLIST_KEY_UIApplicationSupportsIndirectInputEvents[sdk=iphoneos*]" = YES;
Expand All @@ -308,11 +313,12 @@
MARKETING_VERSION = 1.0;
PRODUCT_BUNDLE_IDENTIFIER = "ada-4th-c3.study";
PRODUCT_NAME = "$(TARGET_NAME)";
SDKROOT = auto;
SUPPORTED_PLATFORMS = "iphoneos iphonesimulator macosx xros xrsimulator";
SDKROOT = iphoneos;
SUPPORTED_PLATFORMS = "iphoneos iphonesimulator";
SUPPORTS_MACCATALYST = NO;
SWIFT_EMIT_LOC_STRINGS = YES;
SWIFT_VERSION = 5.0;
TARGETED_DEVICE_FAMILY = "1,2,7";
TARGETED_DEVICE_FAMILY = "1,2";
XROS_DEPLOYMENT_TARGET = 2.2;
};
name = Release;
Expand Down
78 changes: 78 additions & 0 deletions study.xcodeproj/xcshareddata/xcschemes/study.xcscheme
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
LastUpgradeVersion = "1620"
version = "1.7">
<BuildAction
parallelizeBuildables = "YES"
buildImplicitDependencies = "YES"
buildArchitectures = "Automatic">
<BuildActionEntries>
<BuildActionEntry
buildForTesting = "YES"
buildForRunning = "YES"
buildForProfiling = "YES"
buildForArchiving = "YES"
buildForAnalyzing = "YES">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "2415A4472DD0DF8E00EDC236"
BuildableName = "study.app"
BlueprintName = "study"
ReferencedContainer = "container:study.xcodeproj">
</BuildableReference>
</BuildActionEntry>
</BuildActionEntries>
</BuildAction>
<TestAction
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
shouldUseLaunchSchemeArgsEnv = "YES"
shouldAutocreateTestPlan = "YES">
</TestAction>
<LaunchAction
buildConfiguration = "Debug"
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
launchStyle = "0"
useCustomWorkingDirectory = "NO"
ignoresPersistentStateOnLaunch = "NO"
debugDocumentVersioning = "YES"
debugServiceExtension = "internal"
allowLocationSimulation = "YES">
<BuildableProductRunnable
runnableDebuggingMode = "0">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "2415A4472DD0DF8E00EDC236"
BuildableName = "study.app"
BlueprintName = "study"
ReferencedContainer = "container:study.xcodeproj">
</BuildableReference>
</BuildableProductRunnable>
</LaunchAction>
<ProfileAction
buildConfiguration = "Release"
shouldUseLaunchSchemeArgsEnv = "YES"
savedToolIdentifier = ""
useCustomWorkingDirectory = "NO"
debugDocumentVersioning = "YES">
<BuildableProductRunnable
runnableDebuggingMode = "0">
<BuildableReference
BuildableIdentifier = "primary"
BlueprintIdentifier = "2415A4472DD0DF8E00EDC236"
BuildableName = "study.app"
BlueprintName = "study"
ReferencedContainer = "container:study.xcodeproj">
</BuildableReference>
</BuildableProductRunnable>
</ProfileAction>
<AnalyzeAction
buildConfiguration = "Debug">
</AnalyzeAction>
<ArchiveAction
buildConfiguration = "Release"
revealArchiveInOrganizer = "YES">
</ArchiveAction>
</Scheme>
3 changes: 3 additions & 0 deletions study/core/base/BaseView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -28,5 +28,8 @@ struct BaseView<Content: View, State: Any, ViewModel: BaseViewModel<State>>: Vie
.navigationBarBackButtonHidden(navigationBarBackButtonHidden)
.navigationBarHidden(navigationBarHidden)
}
.onDisappear {
viewModel.dispose()
}
}
}
2 changes: 2 additions & 0 deletions study/core/base/BaseViewModel.swift
Original file line number Diff line number Diff line change
Expand Up @@ -18,4 +18,6 @@ class BaseViewModel<State>: ObservableObject {
}
}
}

func dispose() {}
}
29 changes: 29 additions & 0 deletions study/features/audio/FestFourierTransform.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
// Copyright © 2025 ADA 4th Challenge3 Team1. All rights reserved.

import AVFoundation

// DFT(Discrete Fourier Transform)는 O(N^2) 걸림
// FFT(Fest Fourier Transform)는 분할 정복으로 계산량을 O(NLogN)으로 줄임
// 길이 n의 신호를 짝수 인덱스 샘플과 홀수 인덱스 샘플로 나눔
class FestFourierTransform {
func run(_ input: [Complex]) -> [Complex] {
let n = input.count
if n == 1 {
return input
}
if n & (n - 1) != 0 {
fatalError("Input size must be a power of 2")
}
let even = run((0 ..< n / 2).map { input[2 * $0] })
let odd = run((0 ..< n / 2).map { input[2 * $0 + 1] })

var output = Array(repeating: Complex(0, 0), count: n)
for k in 0 ..< n / 2 {
let twiddle = Complex(cos(-2 * Double.pi * Double(k) / Double(n)),
sin(-2 * Double.pi * Double(k) / Double(n)))
output[k] = even[k] + twiddle * odd[k]
output[k + n / 2] = even[k] - twiddle * odd[k]
}
return output
}
}
30 changes: 30 additions & 0 deletions study/features/audio/Recorder.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
// Copyright © 2025 ADA 4th Challenge3 Team1. All rights reserved.

import AVFoundation

class Recorder: ObservableObject {
private var audioEngine = AVAudioEngine()
private var inputNode: AVAudioInputNode?
var inputFormat: AVAudioFormat?

func start(_ windowSize: Int, _ handler: @escaping AVAudioNodeTapBlock) {
do {
let session = AVAudioSession.sharedInstance()
try session.setCategory(.playAndRecord, mode: .default, options: [.defaultToSpeaker])
try session.setPreferredSampleRate(48000)
try session.setActive(true)
} catch {
print("AVAudioSession 설정 중 오류 발생: \(error)")
}

inputNode = audioEngine.inputNode
inputFormat = inputNode!.outputFormat(forBus: 0)
inputNode?.installTap(onBus: 0, bufferSize: AVAudioFrameCount(windowSize), format: inputFormat, block: handler)
try? audioEngine.start()
}

func stop() {
inputNode?.removeTap(onBus: 0)
audioEngine.stop()
}
}
27 changes: 27 additions & 0 deletions study/features/audio/entities/Complex.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
// Copyright © 2025 ADA 4th Challenge3 Team1. All rights reserved.

struct Complex {
// 실수부 (cos 성분)
var real: Double

// 허수부 (sin 성부)
var imag: Double

init(_ real: Double, _ imag: Double) {
self.real = real
self.imag = imag
}

static func + (lhs: Complex, rhs: Complex) -> Complex {
Complex(lhs.real + rhs.real, lhs.imag + rhs.imag)
}

static func - (lhs: Complex, rhs: Complex) -> Complex {
Complex(lhs.real - rhs.real, lhs.imag - rhs.imag)
}

static func * (lhs: Complex, rhs: Complex) -> Complex {
Complex(lhs.real * rhs.real - lhs.imag * rhs.imag,
lhs.real * rhs.imag + lhs.imag * rhs.real)
}
}
1 change: 1 addition & 0 deletions study/presentations/router/RouterView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ struct RouterView: View {
case .todo: TodoView()
case .bucket: BucketView()
case .prototypeSample: PrototypeSampleView()
case .frequencyAnalysis: FrequencyAnalysisView()
}
}
.toolbarBackground(.hidden, for: .navigationBar)
Expand Down
1 change: 1 addition & 0 deletions study/presentations/router/RouterViewState.swift
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ enum SubPage {
case todo
case bucket
case prototypeSample
case frequencyAnalysis
}

struct RouterViewState {
Expand Down
3 changes: 3 additions & 0 deletions study/presentations/views/home/HomeView.swift
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,9 @@ struct HomeView: View {
Tile(title: "Sample", subtitle: "Nickname") {
router.push(.prototypeSample)
}
Tile(title: "Frequency Analysis", subtitle: "Nell") {
router.push(.frequencyAnalysis)
}
}
}
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
// Copyright © 2025 ADA 4th Challenge3 Team1. All rights reserved.

import SwiftUI

struct FrequencyAnalysisView: View {
var body: some View {
BaseView(
create: { FrequencyAnalysisViewModel() }
) { _, state in
VStack {
Toolbar(title: "Frequency Analysis")
Spacer()
Text(state.note)
.font(.title)
Spacer()
}
}
}
}

#Preview {
BasePreview {
FrequencyAnalysisView()
}
}
Loading