@@ -19,22 +19,34 @@ class HornSoundDetector: NSObject, ObservableObject {
19
19
private var inputNode : AVAudioInputNode !
20
20
private var soundClassifier : HornSoundClassifier_V11 ?
21
21
private var streamAnalyzer : SNAudioStreamAnalyzer ?
22
+ //fix 시작
23
+ // @Published var isRecording = false
24
+ // @Published var classificationResult = "녹음 시작 전"
25
+ // @Published var detectedHornSound = false
26
+ // @Published var topClassification: SNClassification? // 가장 높은 분류 저장
27
+ // @Published var mlConfidences: [Double] = Array(repeating: 0.0, count: 4) // 각 채널의 신뢰도 배열
28
+ // private var cancellables = Set<AnyCancellable>()
22
29
30
+ // override init() {
31
+ //fix 끝
32
+ private var appRootManager : AppRootManager // appRootManager 속성 추가
33
+
23
34
@Published var isRecording = false
24
35
@Published var classificationResult = " 녹음 시작 전 "
25
- @Published var detectedHornSound = false
26
- @Published var topClassification : SNClassification ? // 가장 높은 분류 저장
27
- @Published var mlConfidences : [ Double ] = Array ( repeating: 0.0 , count: 4 ) // 각 채널의 신뢰도 배열
28
36
private var cancellables = Set < AnyCancellable > ( )
29
37
30
- override init ( ) {
38
+ init ( appRootManager: AppRootManager ) {
39
+ self . appRootManager = appRootManager
40
+
31
41
super. init ( )
32
42
setupAudioSession ( )
33
43
setupAudioEngine ( )
34
44
setupSoundClassifier ( )
35
- checkNotificationPermission ( )
45
+ //fix
46
+ // checkNotificationPermission()
36
47
37
48
// 앱이 백그라운드로 전환될 때 녹음을 중지하도록 옵저버 설정
49
+ //fix
38
50
NotificationCenter . default. addObserver ( self , selector: #selector( stopRecording) , name: UIApplication . didEnterBackgroundNotification, object: nil )
39
51
}
40
52
@@ -47,11 +59,22 @@ class HornSoundDetector: NSObject, ObservableObject {
47
59
print ( " 오디오 세션 설정 실패: \( error) " )
48
60
}
49
61
}
62
+ //fix
63
+ // private func setupAudioEngine() {
64
+ // audioEngine = AVAudioEngine()
65
+ // inputNode = audioEngine.inputNode
66
+ // }
67
+
68
+ //fix
69
+
50
70
private func setupAudioEngine( ) {
51
71
audioEngine = AVAudioEngine ( )
52
72
inputNode = audioEngine. inputNode
73
+ let format = inputNode. outputFormat ( forBus: 0 )
74
+ let monoFormat = AVAudioFormat ( commonFormat: format. commonFormat, sampleRate: format. sampleRate, channels: 1 , interleaved: format. isInterleaved)
75
+ streamAnalyzer = SNAudioStreamAnalyzer ( format: monoFormat ?? format)
53
76
}
54
-
77
+
55
78
private func setupSoundClassifier( ) {
56
79
do {
57
80
let config = MLModelConfiguration ( )
@@ -62,59 +85,79 @@ class HornSoundDetector: NSObject, ObservableObject {
62
85
print ( " 소리 분류기 생성 실패: \( error) " )
63
86
}
64
87
}
88
+ //fix
65
89
66
- private func checkNotificationPermission( ) {
67
- UNUserNotificationCenter . current ( ) . getNotificationSettings { settings in
68
- switch settings. authorizationStatus {
69
- case . notDetermined:
70
- self . requestNotificationPermission ( )
71
- case . denied:
72
- print ( " 알림 권한이 거부되었습니다. 설정에서 권한을 변경해주세요. " )
73
- case . authorized, . provisional, . ephemeral:
74
- print ( " 알림 권한이 허용되었습니다. " )
75
- @unknown default :
76
- break
77
- }
78
- }
79
- }
90
+ // private func checkNotificationPermission() {
91
+ // UNUserNotificationCenter.current().getNotificationSettings { settings in
92
+ // switch settings.authorizationStatus {
93
+ // case .notDetermined:
94
+ // self.requestNotificationPermission()
95
+ // case .denied:
96
+ // print("알림 권한이 거부되었습니다. 설정에서 권한을 변경해주세요.")
97
+ // case .authorized, .provisional, .ephemeral:
98
+ // print("알림 권한이 허용되었습니다.")
99
+ // @unknown default:
100
+ // break
101
+ // }
102
+ // }
103
+ // }
80
104
81
- private func requestNotificationPermission( ) {
82
- UNUserNotificationCenter . current ( ) . requestAuthorization ( options: [ . alert, . sound] ) { granted, error in
83
- if granted {
84
- print ( " 알림 권한이 허용되었습니다. " )
85
- } else if let error = error {
86
- print ( " 알림 권한 요청 중 오류 발생: \( error. localizedDescription) " )
87
- }
88
- }
89
- }
105
+ // private func requestNotificationPermission() {
106
+ // UNUserNotificationCenter.current().requestAuthorization(options: [.alert, .sound]) { granted, error in
107
+ // if granted {
108
+ // print("알림 권한이 허용되었습니다.")
109
+ // } else if let error = error {
110
+ // print("알림 권한 요청 중 오류 발생: \(error.localizedDescription)")
111
+ // }
112
+ // }
113
+ // }
90
114
115
+ //fix
116
+
117
+
91
118
func startRecording( ) {
92
119
guard !isRecording else {
93
120
print ( " 녹음이 이미 시작된 상태입니다. " )
94
121
return
95
122
}
123
+ //fix
96
124
97
- let format = inputNode. outputFormat ( forBus: 0 )
98
- streamAnalyzer = SNAudioStreamAnalyzer ( format: format)
125
+ // let format = inputNode.outputFormat(forBus: 0)
126
+ // streamAnalyzer = SNAudioStreamAnalyzer(format: format)
99
127
100
- guard let streamAnalyzer = streamAnalyzer,
101
- let soundClassifier = soundClassifier else {
128
+ // guard let streamAnalyzer = streamAnalyzer,
129
+ // let soundClassifier = soundClassifier else {
130
+ // print("스트림 분석기 또는 소리 분류기 생성 실패")
131
+ // return
132
+ // }
133
+ //fix
134
+ guard let streamAnalyzer = streamAnalyzer, let soundClassifier = soundClassifier else {
102
135
print ( " 스트림 분석기 또는 소리 분류기 생성 실패 " )
103
136
return
104
137
}
105
-
138
+
139
+
106
140
do {
107
141
let request = try SNClassifySoundRequest ( mlModel: soundClassifier. model)
108
142
try streamAnalyzer. add ( request, withObserver: self )
109
143
} catch {
110
144
print ( " 분류 요청 생성 실패: \( error) " )
111
145
return
112
146
}
147
+ // //fix
148
+
149
+ // inputNode.installTap(onBus: 0, bufferSize: 8192, format: format) { [weak self] buffer, time in
150
+ // self?.streamAnalyzer?.analyze(buffer, atAudioFramePosition: time.sampleTime)
151
+ // }
113
152
153
+ //fix
154
+
155
+ let format = inputNode. outputFormat ( forBus: 0 )
114
156
inputNode. installTap ( onBus: 0 , bufferSize: 8192 , format: format) { [ weak self] buffer, time in
115
157
self ? . streamAnalyzer? . analyze ( buffer, atAudioFramePosition: time. sampleTime)
116
158
}
117
-
159
+
160
+
118
161
audioEngine. prepare ( )
119
162
do {
120
163
try audioEngine. start ( )
@@ -125,7 +168,7 @@ class HornSoundDetector: NSObject, ObservableObject {
125
168
print ( " 오디오 엔진 시작 실패: \( error) " )
126
169
}
127
170
}
128
-
171
+
129
172
@objc func stopRecording( ) {
130
173
guard isRecording else {
131
174
print ( " 녹음이 이미 중지된 상태입니다. " )
@@ -138,9 +181,11 @@ class HornSoundDetector: NSObject, ObservableObject {
138
181
isRecording = false
139
182
print ( " 오디오 엔진 중지됨 " )
140
183
}
184
+
141
185
142
186
func sendNotification( title: String , body: String ) {
143
187
print ( " 알림 발송 시도 " )
188
+
144
189
let content = UNMutableNotificationContent ( )
145
190
content. title = title
146
191
content. body = body
@@ -161,25 +206,39 @@ extension HornSoundDetector: SNResultsObserving {
161
206
func request( _ request: SNRequest , didProduce result: SNResult ) {
162
207
guard let result = result as? SNClassificationResult else { return }
163
208
164
- let topClassifications = result. classifications. prefix ( 3 )
209
+ //fix
210
+ // let topClassifications = result.classifications.prefix(3)
165
211
166
- DispatchQueue . main. async {
167
- // 첫 번째 분류를 가장 신뢰도 높은 것으로 설정
168
- if let topClassification = topClassifications. first ( where: { classification in
169
- return classification. identifier == " Bicyclebell " || classification. identifier == " Carhorn " || classification. identifier == " Siren "
170
- } ) {
171
- self . topClassification = topClassification // 가장 높은 분류 저장
172
- self . classificationResult = topClassification. identifier // 소리 종류만 저장
173
- }
212
+ // DispatchQueue.main.async {
213
+ // // 첫 번째 분류를 가장 신뢰도 높은 것으로 설정
214
+ // if let topClassification = topClassifications.first(where: { classification in
215
+ // return classification.identifier == "Bicyclebell" || classification.identifier == "Carhorn" || classification.identifier == "Siren"
216
+ // }) {
217
+ // self.topClassification = topClassification // 가장 높은 분류 저장
218
+ // self.classificationResult = topClassification.identifier // 소리 종류만 저장
219
+ // }
174
220
175
- for (index, classification) in topClassifications. enumerated ( ) {
176
- if classification. identifier == " Bicyclebell " || classification. identifier == " Carhorn " || classification. identifier == " Siren " {
177
- // 경적 및 사이렌 소리 감지
178
- if classification. confidence >= 1.0 {
179
- self . mlConfidences [ index] = classification. confidence
180
- // 원하는 로직을 추가하세요
181
- }
221
+ // for (index, classification) in topClassifications.enumerated() {
222
+ // if classification.identifier == "Bicyclebell" || classification.identifier == "Carhorn" || classification.identifier == "Siren" {
223
+ // // 경적 및 사이렌 소리 감지
224
+ // if classification.confidence >= 1.0 {
225
+ // self.mlConfidences[index] = classification.confidence
226
+ // // 원하는 로직을 추가하세요
227
+ // }
228
+ // }
229
+ //fix
230
+ DispatchQueue . main. async {
231
+ if let topClassification = result. classifications. first, topClassification. confidence >= 1.0 {
232
+ let isRelevantSound = [ " Bicyclebell " , " Carhorn " , " Siren " ] . contains ( topClassification. identifier)
233
+ if isRelevantSound {
234
+ self . classificationResult = topClassification. identifier
235
+ self . appRootManager. detectedSound = topClassification. identifier
236
+ self . appRootManager. currentRoot = . warning // 루트 변경
237
+ print ( " 감지된 소리: \( topClassification. identifier) - 신뢰도: \( topClassification. confidence) " )
182
238
}
239
+ } else {
240
+ print ( " 신뢰도 부족 또는 관련 없는 소리 감지됨 " )
241
+
183
242
}
184
243
}
185
244
}
0 commit comments